Skip to content

Commit 2d40186

Browse files
authored
REF: simplify setitem_with_indexer (#37881)
1 parent fef84f4 commit 2d40186

File tree

3 files changed

+23
-39
lines changed

3 files changed

+23
-39
lines changed

pandas/core/indexing.py

+21-31
Original file line numberDiff line numberDiff line change
@@ -1647,6 +1647,8 @@ def _setitem_with_indexer_split_path(self, indexer, value):
16471647
indexer = _tuplify(self.ndim, indexer)
16481648
if len(indexer) > self.ndim:
16491649
raise IndexError("too many indices for array")
1650+
if isinstance(indexer[0], np.ndarray) and indexer[0].ndim > 2:
1651+
raise ValueError(r"Cannot set values with ndim > 2")
16501652

16511653
if isinstance(value, ABCSeries):
16521654
value = self._align_series(indexer, value)
@@ -1658,57 +1660,45 @@ def _setitem_with_indexer_split_path(self, indexer, value):
16581660
lplane_indexer = length_of_indexer(pi, self.obj.index)
16591661
# lplane_indexer gives the expected length of obj[indexer[0]]
16601662

1661-
if len(ilocs) == 1:
1662-
# We can operate on a single column
1663-
1664-
# require that we are setting the right number of values that
1665-
# we are indexing
1666-
if is_list_like_indexer(value) and 0 != lplane_indexer != len(value):
1667-
# Exclude zero-len for e.g. boolean masking that is all-false
1668-
raise ValueError(
1669-
"cannot set using a multi-index "
1670-
"selection indexer with a different "
1671-
"length than the value"
1672-
)
1673-
16741663
# we need an iterable, with a ndim of at least 1
16751664
# eg. don't pass through np.array(0)
16761665
if is_list_like_indexer(value) and getattr(value, "ndim", 1) > 0:
16771666

1678-
# we have an equal len Frame
16791667
if isinstance(value, ABCDataFrame):
16801668
self._setitem_with_indexer_frame_value(indexer, value)
16811669

1682-
# we have an equal len ndarray/convertible to our ilocs
1683-
# hasattr first, to avoid coercing to ndarray without reason.
1684-
# But we may be relying on the ndarray coercion to check ndim.
1685-
# Why not just convert to an ndarray earlier on if needed?
16861670
elif np.ndim(value) == 2:
16871671
self._setitem_with_indexer_2d_value(indexer, value)
16881672

16891673
elif len(ilocs) == 1 and lplane_indexer == len(value) and not is_scalar(pi):
1690-
# we have an equal len list/ndarray
1691-
# We only get here with len(ilocs) == 1
1674+
# We are setting multiple rows in a single column.
16921675
self._setitem_single_column(ilocs[0], value, pi)
16931676

1677+
elif len(ilocs) == 1 and 0 != lplane_indexer != len(value):
1678+
# We are trying to set N values into M entries of a single
1679+
# column, which is invalid for N != M
1680+
# Exclude zero-len for e.g. boolean masking that is all-false
1681+
raise ValueError(
1682+
"Must have equal len keys and value "
1683+
"when setting with an iterable"
1684+
)
1685+
16941686
elif lplane_indexer == 0 and len(value) == len(self.obj.index):
16951687
# We get here in one case via .loc with a all-False mask
16961688
pass
16971689

1698-
else:
1699-
# per-label values
1700-
if len(ilocs) != len(value):
1701-
raise ValueError(
1702-
"Must have equal len keys and value "
1703-
"when setting with an iterable"
1704-
)
1705-
1690+
elif len(ilocs) == len(value):
1691+
# We are setting multiple columns in a single row.
17061692
for loc, v in zip(ilocs, value):
17071693
self._setitem_single_column(loc, v, pi)
1708-
else:
17091694

1710-
if isinstance(indexer[0], np.ndarray) and indexer[0].ndim > 2:
1711-
raise ValueError(r"Cannot set values with ndim > 2")
1695+
else:
1696+
raise ValueError(
1697+
"Must have equal len keys and value "
1698+
"when setting with an iterable"
1699+
)
1700+
1701+
else:
17121702

17131703
# scalar value
17141704
for loc in ilocs:

pandas/tests/indexing/multiindex/test_setitem.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,7 @@ def test_multiindex_assignment(self):
203203
tm.assert_series_equal(df.loc[4, "c"], exp)
204204

205205
# invalid assignments
206-
msg = (
207-
"cannot set using a multi-index selection indexer "
208-
"with a different length than the value"
209-
)
206+
msg = "Must have equal len keys and value when setting with an iterable"
210207
with pytest.raises(ValueError, match=msg):
211208
df.loc[4, "c"] = [0, 1, 2, 3]
212209

pandas/tests/indexing/test_indexing.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,7 @@ def test_setitem_ndarray_1d(self):
3333
df["bar"] = np.zeros(10, dtype=complex)
3434

3535
# invalid
36-
msg = (
37-
"cannot set using a multi-index selection "
38-
"indexer with a different length than the value"
39-
)
36+
msg = "Must have equal len keys and value when setting with an iterable"
4037
with pytest.raises(ValueError, match=msg):
4138
df.loc[df.index[2:5], "bar"] = np.array([2.33j, 1.23 + 0.1j, 2.2, 1.0])
4239

0 commit comments

Comments
 (0)