summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--numpy/lib/arraysetops.py20
-rw-r--r--numpy/lib/tests/test_arraysetops.py31
2 files changed, 41 insertions, 10 deletions
diff --git a/numpy/lib/arraysetops.py b/numpy/lib/arraysetops.py
index fa332e7fd..cf5f47a82 100644
--- a/numpy/lib/arraysetops.py
+++ b/numpy/lib/arraysetops.py
@@ -621,28 +621,28 @@ def in1d(ar1, ar2, assume_unique=False, invert=False, *, kind=None):
# Ensure that iteration through object arrays yields size-1 arrays
if ar2.dtype == object:
ar2 = ar2.reshape(-1, 1)
- # Convert booleans to uint8 so we can use the fast integer algorithm
- if ar1.dtype == bool:
- ar1 = ar1 + np.uint8(0)
- if ar2.dtype == bool:
- ar2 = ar2 + np.uint8(0)
-
- # Check if we can use a fast integer algorithm:
- integer_arrays = (np.issubdtype(ar1.dtype, np.integer) and
- np.issubdtype(ar2.dtype, np.integer))
if kind not in {None, 'sort', 'table'}:
raise ValueError(
f"Invalid kind: '{kind}'. Please use None, 'sort' or 'table'.")
- if integer_arrays and kind in {None, 'table'}:
+ # Can use the table method if all arrays are integers or boolean:
+ is_int_arrays = all(ar.dtype.kind in ("u", "i", "b") for ar in (ar1, ar2))
+ use_table_method = is_int_arrays and kind in {None, 'table'}
+ if use_table_method:
if ar2.size == 0:
if invert:
return np.ones_like(ar1, dtype=bool)
else:
return np.zeros_like(ar1, dtype=bool)
+ # Convert booleans to uint8 so we can use the fast integer algorithm
+ if ar1.dtype == bool:
+ ar1 = ar1.astype(np.uint8)
+ if ar2.dtype == bool:
+ ar2 = ar2.astype(np.uint8)
+
ar2_min = np.min(ar2)
ar2_max = np.max(ar2)
diff --git a/numpy/lib/tests/test_arraysetops.py b/numpy/lib/tests/test_arraysetops.py
index a21e5f640..bb07e25a9 100644
--- a/numpy/lib/tests/test_arraysetops.py
+++ b/numpy/lib/tests/test_arraysetops.py
@@ -396,6 +396,37 @@ class TestSetOps:
assert_array_equal(np.invert(expected),
in1d(a, b, invert=True, kind=kind))
+ @pytest.mark.parametrize("kind", [None, "sort"])
+ def test_in1d_timedelta(self, kind):
+ """Test that in1d works for timedelta input"""
+ rstate = np.random.RandomState(0)
+ a = rstate.randint(0, 100, size=10)
+ b = rstate.randint(0, 100, size=10)
+ truth = in1d(a, b)
+ a_timedelta = a.astype("timedelta64[s]")
+ b_timedelta = b.astype("timedelta64[s]")
+ assert_array_equal(truth, in1d(a_timedelta, b_timedelta, kind=kind))
+
+ def test_in1d_table_timedelta_fails(self):
+ a = np.array([0, 1, 2], dtype="timedelta64[s]")
+ b = a
+ # Make sure it raises a value error:
+ with pytest.raises(ValueError):
+ in1d(a, b, kind="table")
+
+ @pytest.mark.parametrize("kind", [None, "sort", "table"])
+ def test_in1d_mixed_boolean(self, kind):
+ """Test that in1d works as expected for bool/int input."""
+ for dtype in np.typecodes["AllInteger"]:
+ a = np.array([True, False, False], dtype=bool)
+ b = np.array([1, 1, 1, 1], dtype=dtype)
+ expected = np.array([True, False, False], dtype=bool)
+ assert_array_equal(in1d(a, b, kind=kind), expected)
+
+ a, b = b, a
+ expected = np.array([True, True, True, True], dtype=bool)
+ assert_array_equal(in1d(a, b, kind=kind), expected)
+
def test_in1d_first_array_is_object(self):
ar1 = [None]
ar2 = np.array([1]*10)