Repository: pandas-dev/pandas

Issue:
REGR: Setting values with 'loc' and boolean mask mixes up values (all-True mask)
According to [documentation](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.loc.html), using `loc` should work with Boolean arrays. However, the following does not seem to work: 

```python
import pandas as pd

n = 17

data = pd.DataFrame({
    "name": n * ["a"], 
    "x": range(n), 
    "y": range(n)
})

copy = data.copy()

idx = n * [True]
data.loc[idx, ["x", "y"]] = data[["x", "y"]]
assert data.equals(copy)   # Raises assertion error
```

The weird thing is that if n is smaller then the code works. This has been tested on Pandas 1.5.0


Discussion:
I believe that this is a regression in pandas 1.5.0 as this works correctly on 1.4.4. We ran into the same bug in downstream yesterday https://github.com/geopandas/geopandas/issues/2558. 
The reproducer from that issue:

```
In [1]: df = pd.DataFrame({'idx': range(20), 'col': np.arange(20, dtype="float")})

In [2]: df.loc[np.ones(len(df), dtype=bool), 'col'] = df.col.values

In [3]: df
Out[3]: 
    idx   col
0     0   0.0
1     1  17.0
2     2  16.0
3     3  15.0
4     4  14.0
5     5  13.0
6     6  12.0
7     7  11.0
8     8  10.0
9     9   9.0
10   10   8.0
11   11   7.0
12   12   6.0
13   13   5.0
14   14   4.0
15   15   3.0
16   16   2.0
17   17   1.0
18   18  18.0
19   19  19.0
```

> The weird thing is that if n is smaller then the code works. 

It indeed needs some minimum values, because of `np.argsort` only starting to return non-sorted values after a minimum number of True values:

```
In [4]: np.argsort([True]*10)
Out[4]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [5]: np.argsort([True]*17)
Out[5]: array([ 0, 14, 13, 12, 11, 10,  9, 15,  8,  6,  5,  4,  3,  2,  1,  7, 16])
```

This argsort is used here:

https://github.com/pandas-dev/pandas/blob/71fc89cd515c3c19230fbab64e979118858b808a/pandas/core/indexing.py#L1990

That code assumes that indexer is already an integer indexer, not a boolean one. Before, we converted a boolean indexer to integers in `_locIndexer._convert_to_indexer`, but this was removed in https://github.com/pandas-dev/pandas/pull/45501 ([location in diff](https://github.com/pandas-dev/pandas/pull/45501/files#diff-07282871a235456baecd3a55a43339b0da374ca270228b5530f5449aabdca2e1L1303)). 

I haven't verified to be 100% sure, but so given the code path and the change in https://github.com/pandas-dev/pandas/pull/45501, I assume that's the cause.
> I haven't verified to be 100% sure, but so given the code path and the change in https://github.com/pandas-dev/pandas/pull/45501, I assume that's the cause.

yup, [git bisect confirms](https://www.kaggle.com/code/marcogorelli/pandas-regression-48701?scriptVersionId=106277631)

Patch:
diff --git a/doc/source/whatsnew/v1.5.1.rst b/doc/source/whatsnew/v1.5.1.rst
index 4a7eaf20a8745..4717c6fcf5ea1 100644
--- a/doc/source/whatsnew/v1.5.1.rst
+++ b/doc/source/whatsnew/v1.5.1.rst
@@ -14,6 +14,7 @@ including other versions of pandas.
 
 Fixed regressions
 ~~~~~~~~~~~~~~~~~
+- Fixed Regression in :meth:`DataFrame.loc` when setting values as a :class:`DataFrame` with all ``True`` indexer (:issue:`48701`)
 - Regression in :func:`.read_csv` causing an ``EmptyDataError`` when using an UTF-8 file handle that was already read from (:issue:`48646`)
 - Fixed performance regression in :func:`factorize` when ``na_sentinel`` is not ``None`` and ``sort=False`` (:issue:`48620`)
 -
diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py
index 37d211d4d3cf0..923c6c965c1c2 100644
--- a/pandas/core/indexing.py
+++ b/pandas/core/indexing.py
@@ -1986,7 +1986,7 @@ def _setitem_single_column(self, loc: int, value, plane_indexer) -> None:
             and self.obj.shape[0] == value.shape[0]
             and not is_empty_indexer(pi)
         ):
-            if is_list_like(pi):
+            if is_list_like(pi) and not is_bool_dtype(pi):
                 value = value[np.argsort(pi)]
             else:
                 # in case of slice


Test patch:
diff --git a/pandas/tests/frame/indexing/test_indexing.py b/pandas/tests/frame/indexing/test_indexing.py
index 7f84d8a367eac..3062dff27d537 100644
--- a/pandas/tests/frame/indexing/test_indexing.py
+++ b/pandas/tests/frame/indexing/test_indexing.py
@@ -1405,6 +1405,15 @@ def test_loc_named_tuple_for_midx(self):
         )
         tm.assert_frame_equal(result, expected)
 
+    @pytest.mark.parametrize("col", [{}, {"name": "a"}])
+    def test_loc_setitem_reordering_with_all_true_indexer(self, col):
+        # GH#48701
+        n = 17
+        df = DataFrame({**col, "x": range(n), "y": range(n)})
+        expected = df.copy()
+        df.loc[n * [True], ["x", "y"]] = df[["x", "y"]]
+        tm.assert_frame_equal(df, expected)
+
 
 class TestDataFrameIndexingUInt64:
     def test_setitem(self, uint64_frame):