Skip to content

Commit 8022743

Browse files
authored
REF: implement is_exact_match (#39149)
1 parent 4ecba51 commit 8022743

File tree

3 files changed

+34
-15
lines changed

3 files changed

+34
-15
lines changed

pandas/core/indexers.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import numpy as np
77

8-
from pandas._typing import Any, AnyArrayLike
8+
from pandas._typing import Any, AnyArrayLike, ArrayLike
99

1010
from pandas.core.dtypes.common import (
1111
is_array_like,
@@ -270,6 +270,27 @@ def maybe_convert_indices(indices, n: int):
270270
# Unsorted
271271

272272

273+
def is_exact_shape_match(target: ArrayLike, value: ArrayLike) -> bool:
274+
"""
275+
Is setting this value into this target overwriting the entire column?
276+
277+
Parameters
278+
----------
279+
target : np.ndarray or ExtensionArray
280+
value : np.ndarray or ExtensionArray
281+
282+
Returns
283+
-------
284+
bool
285+
"""
286+
return (
287+
len(value.shape) > 0
288+
and len(target.shape) > 0
289+
and value.shape[0] == target.shape[0]
290+
and value.size == target.size
291+
)
292+
293+
273294
def length_of_indexer(indexer, target=None) -> int:
274295
"""
275296
Return the expected length of target[indexer]

pandas/core/indexing.py

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from pandas.core.construction import array as pd_array
3434
from pandas.core.indexers import (
3535
check_array_indexer,
36+
is_exact_shape_match,
3637
is_list_like_indexer,
3738
length_of_indexer,
3839
)
@@ -1815,6 +1816,9 @@ def _setitem_single_column(self, loc: int, value, plane_indexer):
18151816
# GH#6149 (null slice), GH#10408 (full bounds)
18161817
if com.is_null_slice(pi) or com.is_full_slice(pi, len(self.obj)):
18171818
ser = value
1819+
elif is_array_like(value) and is_exact_shape_match(ser, value):
1820+
ser = value
1821+
18181822
else:
18191823
# set the item, possibly having a dtype change
18201824
ser = ser.copy()

pandas/core/internals/blocks.py

+8-14
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
from pandas.core.indexers import (
7676
check_setitem_lengths,
7777
is_empty_indexer,
78+
is_exact_shape_match,
7879
is_scalar_indexer,
7980
)
8081
import pandas.core.missing as missing
@@ -903,15 +904,7 @@ def setitem(self, indexer, value):
903904

904905
# coerce if block dtype can store value
905906
values = self.values
906-
if self._can_hold_element(value):
907-
# We only get here for non-Extension Blocks, so _try_coerce_args
908-
# is only relevant for DatetimeBlock and TimedeltaBlock
909-
if self.dtype.kind in ["m", "M"]:
910-
arr = self.array_values().T
911-
arr[indexer] = value
912-
return self
913-
914-
else:
907+
if not self._can_hold_element(value):
915908
# current dtype cannot store value, coerce to common dtype
916909
# TODO: can we just use coerce_to_target_dtype for all this
917910
if hasattr(value, "dtype"):
@@ -932,6 +925,11 @@ def setitem(self, indexer, value):
932925

933926
return self.astype(dtype).setitem(indexer, value)
934927

928+
if self.dtype.kind in ["m", "M"]:
929+
arr = self.array_values().T
930+
arr[indexer] = value
931+
return self
932+
935933
# value must be storable at this moment
936934
if is_extension_array_dtype(getattr(value, "dtype", None)):
937935
# We need to be careful not to allow through strings that
@@ -947,11 +945,7 @@ def setitem(self, indexer, value):
947945

948946
# length checking
949947
check_setitem_lengths(indexer, value, values)
950-
exact_match = (
951-
len(arr_value.shape)
952-
and arr_value.shape[0] == values.shape[0]
953-
and arr_value.size == values.size
954-
)
948+
exact_match = is_exact_shape_match(values, arr_value)
955949
if is_empty_indexer(indexer, arr_value):
956950
# GH#8669 empty indexers
957951
pass

0 commit comments

Comments
 (0)