diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index fb542711329b4..82971e460a8a2 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -1873,7 +1873,11 @@ def _setitem_single_column(self, loc: int, value, plane_indexer): if com.is_null_slice(pi) or com.is_full_slice(pi, len(self.obj)): ser = value elif is_array_like(value) and is_exact_shape_match(ser, value): - ser = value + if is_list_like(pi): + ser = value[np.argsort(pi)] + else: + # in case of slice + ser = value[pi] else: # set the item, possibly having a dtype change ser = ser.copy() diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py index eac46fb64b65e..97b3412ce626e 100644 --- a/pandas/tests/indexing/test_loc.py +++ b/pandas/tests/indexing/test_loc.py @@ -597,17 +597,13 @@ def test_loc_setitem_frame_with_reindex(self, using_array_manager): ser = Series([2, 3, 1], index=[3, 5, 4], dtype=float) if using_array_manager: # TODO(ArrayManager) with "split" path, we still overwrite the column - # and therefore don't take the order of the indexer into account - ser = Series([1, 2, 3], index=[3, 5, 4], dtype="int64") + # and therefore don't take the dtype of the underlying object into account + ser = Series([2, 3, 1], index=[3, 5, 4], dtype="int64") expected = DataFrame({"A": ser}) tm.assert_frame_equal(df, expected) - @pytest.mark.xfail(reason="split path wrong update - GH40480") def test_loc_setitem_frame_with_reindex_mixed(self): - # same test as above, but with mixed dataframe - # TODO with "split" path we still actually overwrite the column - # and therefore don't take the order of the indexer into account - # -> this is a bug: https://github.com/pandas-dev/pandas/issues/40480 + # GH#40480 df = DataFrame(index=[3, 5, 4], columns=["A", "B"], dtype=float) df["B"] = "string" df.loc[[4, 3, 5], "A"] = np.array([1, 2, 3], dtype="int64") @@ -616,8 +612,16 @@ def test_loc_setitem_frame_with_reindex_mixed(self): expected["B"] = "string" tm.assert_frame_equal(df, expected) + def test_loc_setitem_frame_with_inverted_slice(self): + # GH#40480 + df = DataFrame(index=[1, 2, 3], columns=["A", "B"], dtype=float) + df["B"] = "string" + df.loc[slice(3, 0, -1), "A"] = np.array([1, 2, 3], dtype="int64") + expected = DataFrame({"A": [3, 2, 1], "B": "string"}, index=[1, 2, 3]) + tm.assert_frame_equal(df, expected) + # TODO(ArrayManager) "split" path overwrites column and therefore don't take - # the order of the indexer into account + # the dtype of the underlying object into account @td.skip_array_manager_not_yet_implemented def test_loc_setitem_empty_frame(self): # GH#6252 setting with an empty frame