Skip to content

Commit 085f27b

Browse files
authored
REF: remove ObjectBlock._replace_single (#37710)
1 parent 8b6f091 commit 085f27b

File tree

1 file changed

+62
-73
lines changed

1 file changed

+62
-73
lines changed

pandas/core/internals/blocks.py

+62-73
Original file line numberDiff line numberDiff line change
@@ -813,17 +813,50 @@ def replace(
813813
)
814814
return blocks
815815

816-
def _replace_single(
816+
def _replace_regex(
817817
self,
818818
to_replace,
819819
value,
820820
inplace: bool = False,
821-
regex: bool = False,
822821
convert: bool = True,
823822
mask=None,
824823
) -> List["Block"]:
825-
""" no-op on a non-ObjectBlock """
826-
return [self] if inplace else [self.copy()]
824+
"""
825+
Replace elements by the given value.
826+
827+
Parameters
828+
----------
829+
to_replace : object or pattern
830+
Scalar to replace or regular expression to match.
831+
value : object
832+
Replacement object.
833+
inplace : bool, default False
834+
Perform inplace modification.
835+
convert : bool, default True
836+
If true, try to coerce any object types to better types.
837+
mask : array-like of bool, optional
838+
True indicate corresponding element is ignored.
839+
840+
Returns
841+
-------
842+
List[Block]
843+
"""
844+
if not self._can_hold_element(to_replace):
845+
# i.e. only ObjectBlock, but could in principle include a
846+
# String ExtensionBlock
847+
return [self] if inplace else [self.copy()]
848+
849+
rx = re.compile(to_replace)
850+
851+
new_values = self.values if inplace else self.values.copy()
852+
replace_regex(new_values, rx, value, mask)
853+
854+
block = self.make_block(new_values)
855+
if convert:
856+
nbs = block.convert(numeric=False)
857+
else:
858+
nbs = [block]
859+
return nbs
827860

828861
def _replace_list(
829862
self,
@@ -1598,14 +1631,16 @@ def _replace_coerce(
15981631
self = self.coerce_to_target_dtype(value)
15991632
return self.putmask(mask, value, inplace=inplace)
16001633
else:
1601-
return self._replace_single(
1602-
to_replace,
1603-
value,
1604-
inplace=inplace,
1605-
regex=regex,
1606-
convert=False,
1607-
mask=mask,
1608-
)
1634+
regex = _should_use_regex(regex, to_replace)
1635+
if regex:
1636+
return self._replace_regex(
1637+
to_replace,
1638+
value,
1639+
inplace=inplace,
1640+
convert=False,
1641+
mask=mask,
1642+
)
1643+
return self.replace(to_replace, value, inplace=inplace, regex=False)
16091644
return [self]
16101645

16111646

@@ -2506,72 +2541,26 @@ def replace(
25062541
# here with listlike to_replace or value, as those cases
25072542
# go through _replace_list
25082543

2509-
if is_re(to_replace) or regex:
2510-
return self._replace_single(to_replace, value, inplace=inplace, regex=True)
2511-
else:
2512-
return super().replace(to_replace, value, inplace=inplace, regex=regex)
2513-
2514-
def _replace_single(
2515-
self,
2516-
to_replace,
2517-
value,
2518-
inplace: bool = False,
2519-
regex: bool = False,
2520-
convert: bool = True,
2521-
mask=None,
2522-
) -> List["Block"]:
2523-
"""
2524-
Replace elements by the given value.
2525-
2526-
Parameters
2527-
----------
2528-
to_replace : object or pattern
2529-
Scalar to replace or regular expression to match.
2530-
value : object
2531-
Replacement object.
2532-
inplace : bool, default False
2533-
Perform inplace modification.
2534-
regex : bool, default False
2535-
If true, perform regular expression substitution.
2536-
convert : bool, default True
2537-
If true, try to coerce any object types to better types.
2538-
mask : array-like of bool, optional
2539-
True indicate corresponding element is ignored.
2540-
2541-
Returns
2542-
-------
2543-
List[Block]
2544-
"""
2545-
inplace = validate_bool_kwarg(inplace, "inplace")
2546-
2547-
# to_replace is regex compilable
2548-
regex = regex and is_re_compilable(to_replace)
2544+
regex = _should_use_regex(regex, to_replace)
25492545

2550-
# try to get the pattern attribute (compiled re) or it's a string
2551-
if is_re(to_replace):
2552-
pattern = to_replace.pattern
2546+
if regex:
2547+
return self._replace_regex(to_replace, value, inplace=inplace)
25532548
else:
2554-
pattern = to_replace
2549+
return super().replace(to_replace, value, inplace=inplace, regex=False)
25552550

2556-
# if the pattern is not empty and to_replace is either a string or a
2557-
# regex
2558-
if regex and pattern:
2559-
rx = re.compile(to_replace)
2560-
else:
2561-
# if the thing to replace is not a string or compiled regex call
2562-
# the superclass method -> to_replace is some kind of object
2563-
return super().replace(to_replace, value, inplace=inplace, regex=regex)
25642551

2565-
new_values = self.values if inplace else self.values.copy()
2566-
replace_regex(new_values, rx, value, mask)
2552+
def _should_use_regex(regex: bool, to_replace: Any) -> bool:
2553+
"""
2554+
Decide whether to treat `to_replace` as a regular expression.
2555+
"""
2556+
if is_re(to_replace):
2557+
regex = True
25672558

2568-
# convert
2569-
block = self.make_block(new_values)
2570-
if convert:
2571-
nbs = block.convert(numeric=False)
2572-
else:
2573-
nbs = [block]
2574-
return nbs
2559+
regex = regex and is_re_compilable(to_replace)
2560+
2561+
# Don't use regex if the pattern is empty.
2562+
regex = regex and re.compile(to_replace).pattern != ""
2563+
return regex
25752564

25762565

25772566
class CategoricalBlock(ExtensionBlock):

0 commit comments

Comments
 (0)