diff --git a/doc/source/whatsnew/v1.1.4.rst b/doc/source/whatsnew/v1.1.4.rst index 6cb728800dc68..7d35e8b12b9b8 100644 --- a/doc/source/whatsnew/v1.1.4.rst +++ b/doc/source/whatsnew/v1.1.4.rst @@ -28,6 +28,7 @@ Fixed regressions - Fixed regression in certain offsets (:meth:`pd.offsets.Day() ` and below) no longer being hashable (:issue:`37267`) - Fixed regression in :class:`StataReader` which required ``chunksize`` to be manually set when using an iterator to read a dataset (:issue:`37280`) - Fixed regression in setitem with :meth:`DataFrame.iloc` which raised error when trying to set a value while filtering with a boolean list (:issue:`36741`) +- Fixed regression in setitem with a Series getting aligned before setting the values (:issue:`37427`) - Fixed regression in :attr:`MultiIndex.is_monotonic_increasing` returning wrong results with ``NaN`` in at least one of the levels (:issue:`37220`) .. --------------------------------------------------------------------------- diff --git a/pandas/core/series.py b/pandas/core/series.py index b6ff7b33d27cb..18a201674db65 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1037,10 +1037,8 @@ def _set_with_engine(self, key, value): def _set_with(self, key, value): # other: fancy integer or otherwise if isinstance(key, slice): - # extract_array so that if we set e.g. ser[-5:] = ser[:5] - # we get the first five values, and not 5 NaNs indexer = self.index._convert_slice_indexer(key, kind="getitem") - self.iloc[indexer] = extract_array(value, extract_numpy=True) + return self._set_values(indexer, value) else: assert not isinstance(key, tuple) @@ -1058,12 +1056,26 @@ def _set_with(self, key, value): # should be caught by the is_bool_indexer check in __setitem__ if key_type == "integer": if not self.index._should_fallback_to_positional(): - self.loc[key] = value + self._set_labels(key, value) else: - self.iloc[key] = value + self._set_values(key, value) else: self.loc[key] = value + def _set_labels(self, key, value): + key = com.asarray_tuplesafe(key) + indexer: np.ndarray = self.index.get_indexer(key) + mask = indexer == -1 + if mask.any(): + raise KeyError(f"{key[mask]} not in index") + self._set_values(indexer, value) + + def _set_values(self, key, value): + if isinstance(key, Series): + key = key._values + self._mgr = self._mgr.setitem(indexer=key, value=value) + self._maybe_update_cacher() + def _set_value(self, label, value, takeable: bool = False): """ Quickly set single value at passed label. diff --git a/pandas/tests/series/indexing/test_getitem.py b/pandas/tests/series/indexing/test_getitem.py index 6b7cda89a4714..cf03dfb8ca9b7 100644 --- a/pandas/tests/series/indexing/test_getitem.py +++ b/pandas/tests/series/indexing/test_getitem.py @@ -137,3 +137,13 @@ def test_getitem_ndim_deprecated(): s = pd.Series([0, 1]) with tm.assert_produces_warning(FutureWarning): s[:, None] + + +def test_getitem_assignment_series_aligment(): + # https://github.com/pandas-dev/pandas/issues/37427 + # with getitem, when assigning with a Series, it is not first aligned + s = Series(range(10)) + idx = np.array([2, 4, 9]) + s[idx] = Series([10, 11, 12]) + expected = Series([0, 1, 10, 3, 11, 5, 6, 7, 8, 12]) + tm.assert_series_equal(s, expected)