Skip to content

Commit bf8ec16

Browse files
committed
API: Make Series.searchsorted return a scalar, when supplied a scalar
1 parent 6111f64 commit bf8ec16

File tree

6 files changed

+31
-17
lines changed

6 files changed

+31
-17
lines changed

doc/source/whatsnew/v0.24.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,7 @@ Other API Changes
10961096
has an improved ``KeyError`` message, and will not fail on duplicate column names with ``drop=True``. (:issue:`22484`)
10971097
- Slicing a single row of a DataFrame with multiple ExtensionArrays of the same type now preserves the dtype, rather than coercing to object (:issue:`22784`)
10981098
- :class:`DateOffset` attribute `_cacheable` and method `_should_cache` have been removed (:issue:`23118`)
1099+
- :meth:`Series.searchsorted`, when supplied a scalar value to search for, now returns a scalar instead of an array (:issue:`23801`).
10991100
- :meth:`Categorical.searchsorted`, when supplied a scalar value to search for, now returns a scalar instead of an array (:issue:`23466`).
11001101
- :meth:`Categorical.searchsorted` now raises a ``KeyError`` rather that a ``ValueError``, if a searched for key is not found in its categories (:issue:`23466`).
11011102
- :meth:`Index.hasnans` and :meth:`Series.hasnans` now always return a python boolean. Previously, a python or a numpy boolean could be returned, depending on circumstances (:issue:`23294`).

pandas/core/base.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -1338,8 +1338,8 @@ def factorize(self, sort=False, na_sentinel=-1):
13381338
13391339
Parameters
13401340
----------
1341-
value : array_like
1342-
Values to insert into `self`.
1341+
value : scalar or array_like
1342+
Value(s) to insert into `self`.
13431343
side : {'left', 'right'}, optional
13441344
If 'left', the index of the first suitable location found is given.
13451345
If 'right', return the last such index. If there is no suitable
@@ -1350,8 +1350,14 @@ def factorize(self, sort=False, na_sentinel=-1):
13501350
13511351
Returns
13521352
-------
1353-
indices : array of ints
1354-
Array of insertion points with the same shape as `value`.
1353+
int or array of ints
1354+
A scalar or array of insertion points with the
1355+
same shape as `value`.
1356+
1357+
.. versionchanged :: 0.24.0
1358+
Ìf `value`is a scalar, an int is now always returned.
1359+
Previously, scalar inputs returned an 1-item array for
1360+
:class:`Series` and :class:`Categorical`.
13551361
13561362
See Also
13571363
--------
@@ -1372,7 +1378,7 @@ def factorize(self, sort=False, na_sentinel=-1):
13721378
dtype: int64
13731379
13741380
>>> x.searchsorted(4)
1375-
array([3])
1381+
3
13761382
13771383
>>> x.searchsorted([0, 4])
13781384
array([0, 3])
@@ -1389,7 +1395,7 @@ def factorize(self, sort=False, na_sentinel=-1):
13891395
Categories (4, object): [apple < bread < cheese < milk]
13901396
13911397
>>> x.searchsorted('bread')
1392-
array([1]) # Note: an array, not a scalar
1398+
1
13931399
13941400
>>> x.searchsorted(['bread'], side='right')
13951401
array([3])

pandas/core/series.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -2215,8 +2215,10 @@ def __rmatmul__(self, other):
22152215
def searchsorted(self, value, side='left', sorter=None):
22162216
if sorter is not None:
22172217
sorter = ensure_platform_int(sorter)
2218-
return self._values.searchsorted(Series(value)._values,
2219-
side=side, sorter=sorter)
2218+
result = self._values.searchsorted(Series(value)._values,
2219+
side=side, sorter=sorter)
2220+
2221+
return result[0] if is_scalar(value) else result
22202222

22212223
# -------------------------------------------------------------------
22222224
# Combination

pandas/tests/arrays/categorical/test_analytics.py

+2
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,11 @@ def test_searchsorted(self):
8686
# Searching for single item argument, side='left' (default)
8787
res_cat = c1.searchsorted('apple')
8888
assert res_cat == 2
89+
assert tm.is_scalar(res_cat)
8990

9091
res_ser = s1.searchsorted('apple')
9192
assert res_ser == 2
93+
assert tm.is_scalar(res_ser)
9294

9395
# Searching for single item array, side='left' (default)
9496
res_cat = c1.searchsorted(['bread'])

pandas/tests/series/test_analytics.py

+10-8
Original file line numberDiff line numberDiff line change
@@ -1364,17 +1364,19 @@ def test_numpy_repeat(self):
13641364
def test_searchsorted(self):
13651365
s = Series([1, 2, 3])
13661366

1367-
idx = s.searchsorted(1, side='left')
1368-
tm.assert_numpy_array_equal(idx, np.array([0], dtype=np.intp))
1367+
result = s.searchsorted(1, side='left')
1368+
assert tm.is_scalar(result)
1369+
assert result == 0
13691370

1370-
idx = s.searchsorted(1, side='right')
1371-
tm.assert_numpy_array_equal(idx, np.array([1], dtype=np.intp))
1371+
result = s.searchsorted(1, side='right')
1372+
assert tm.is_scalar(result)
1373+
assert result == 1
13721374

13731375
def test_searchsorted_numeric_dtypes_scalar(self):
13741376
s = Series([1, 2, 90, 1000, 3e9])
13751377
r = s.searchsorted(30)
1376-
e = 2
1377-
assert r == e
1378+
assert tm.is_scalar(r)
1379+
assert r == 2
13781380

13791381
r = s.searchsorted([30])
13801382
e = np.array([2], dtype=np.intp)
@@ -1390,8 +1392,8 @@ def test_search_sorted_datetime64_scalar(self):
13901392
s = Series(pd.date_range('20120101', periods=10, freq='2D'))
13911393
v = pd.Timestamp('20120102')
13921394
r = s.searchsorted(v)
1393-
e = 1
1394-
assert r == e
1395+
assert tm.is_scalar(r)
1396+
assert r == 1
13951397

13961398
def test_search_sorted_datetime64_list(self):
13971399
s = Series(pd.date_range('20120101', periods=10, freq='2D'))

pandas/util/testing.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
is_bool, is_categorical_dtype, is_datetime64_dtype, is_datetime64tz_dtype,
2828
is_datetimelike_v_numeric, is_datetimelike_v_object,
2929
is_extension_array_dtype, is_interval_dtype, is_list_like, is_number,
30-
is_period_dtype, is_sequence, is_timedelta64_dtype, needs_i8_conversion)
30+
is_period_dtype, is_scalar, is_sequence, is_timedelta64_dtype,
31+
needs_i8_conversion) # noqa
3132
from pandas.core.dtypes.missing import array_equivalent
3233

3334
import pandas as pd

0 commit comments

Comments
 (0)