Skip to content

Commit 1a553bc

Browse files
committed
ENH: Add is_array_like method
Used for abstracting checks in DataFrame.merge, but the function itself can be quite useful.
1 parent cb91df3 commit 1a553bc

File tree

5 files changed

+56
-5
lines changed

5 files changed

+56
-5
lines changed

pandas/core/dtypes/api.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
is_dict_like,
5656
is_iterator,
5757
is_file_like,
58+
is_array_like,
5859
is_list_like,
5960
is_hashable,
6061
is_named_tuple)

pandas/core/dtypes/inference.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,39 @@ def is_list_like(obj):
267267
not isinstance(obj, string_and_binary_types))
268268

269269

270+
def is_array_like(obj):
271+
"""
272+
Check if the object is array-like.
273+
274+
For an object to be considered array-like, it must be list-like and
275+
have a `dtype` attribute.
276+
277+
Parameters
278+
----------
279+
obj : The object to check.
280+
281+
Returns
282+
-------
283+
is_array_like : bool
284+
Whether `obj` has array-like properties.
285+
286+
Examples
287+
--------
288+
>>> is_array_like(np.array([1, 2, 3]))
289+
True
290+
>>> is_array_like(pd.Series(["a", "b"]))
291+
True
292+
>>> is_array_like(pd.Index(["2016-01-01"]))
293+
True
294+
>>> is_array_like([1, 2, 3])
295+
False
296+
>>> is_array_like(("a", "b"))
297+
False
298+
"""
299+
300+
return is_list_like(obj) and hasattr(obj, "dtype")
301+
302+
270303
def is_nested_list_like(obj):
271304
"""
272305
Check if the object is list-like, and that all of its elements

pandas/core/reshape/merge.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010
from pandas.compat import range, lzip, zip, map, filter
1111
import pandas.compat as compat
1212

13-
from pandas import (Categorical, Series, DataFrame,
13+
from pandas import (Categorical, DataFrame,
1414
Index, MultiIndex, Timedelta)
1515
from pandas.core.frame import _merge_doc
1616
from pandas.core.dtypes.common import (
1717
is_datetime64tz_dtype,
1818
is_datetime64_dtype,
1919
needs_i8_conversion,
2020
is_int64_dtype,
21+
is_array_like,
2122
is_categorical_dtype,
2223
is_integer_dtype,
2324
is_float_dtype,
@@ -817,10 +818,9 @@ def _get_merge_keys(self):
817818

818819
left, right = self.left, self.right
819820
stacklevel = 5 # Number of stack levels from df.merge
820-
list_types = (np.ndarray, Series, Index)
821821

822-
is_lkey = lambda x: isinstance(x, list_types) and len(x) == len(left)
823-
is_rkey = lambda x: isinstance(x, list_types) and len(x) == len(right)
822+
is_lkey = lambda x: is_array_like(x) and len(x) == len(left)
823+
is_rkey = lambda x: is_array_like(x) and len(x) == len(right)
824824

825825
# Note that pd.merge_asof() has separate 'on' and 'by' parameters. A
826826
# user could, for example, request 'left_index' and 'left_by'. In a

pandas/tests/api/test_types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class TestTypes(Base):
3030
'is_period_dtype', 'is_interval', 'is_interval_dtype',
3131
'is_re', 'is_re_compilable',
3232
'is_dict_like', 'is_iterator', 'is_file_like',
33-
'is_list_like', 'is_hashable',
33+
'is_list_like', 'is_hashable', 'is_array_like',
3434
'is_named_tuple',
3535
'pandas_dtype', 'union_categoricals', 'infer_dtype']
3636
deprecated = ['is_any_int_dtype', 'is_floating_dtype', 'is_sequence']

pandas/tests/dtypes/test_inference.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,23 @@ def test_is_list_like_fails(ll):
7878
assert not inference.is_list_like(ll)
7979

8080

81+
def test_is_array_like():
82+
assert inference.is_array_like(Series([]))
83+
assert inference.is_array_like(Series([1, 2]))
84+
assert inference.is_array_like(np.array(["a", "b"]))
85+
assert inference.is_array_like(Index(["2016-01-01"]))
86+
87+
class DtypeList(list):
88+
dtype = "special"
89+
90+
assert inference.is_array_like(DtypeList())
91+
92+
assert not inference.is_array_like([1, 2, 3])
93+
assert not inference.is_array_like(tuple())
94+
assert not inference.is_array_like("foo")
95+
assert not inference.is_array_like(123)
96+
97+
8198
@pytest.mark.parametrize('inner', [
8299
[], [1], (1, ), (1, 2), {'a': 1}, set([1, 'a']), Series([1]),
83100
Series([]), Series(['a']).str, (x for x in range(5))

0 commit comments

Comments
 (0)