Repository: numpy/numpy

Issue:
Inconsistency in setdiff1d return value dtype
I noticed this discrepancy in the dtype of the returned array because it lead to an "Implicitly casting between incompatible kinds" warning down the line:

``` py
In [33]: np.setdiff1d(np.array([1], np.uint32), [], True)
Out[33]: array([1], dtype=uint32)

In [34]: np.setdiff1d(np.array([], np.uint32), [], True)
Out[34]: array([], dtype=bool)
```

It looks like this could be easily fixed in https://github.com/numpy/numpy/blob/50e4eb87370b77792f1f6d21a5edd6ff20abee68/numpy/lib/arraysetops.py#L478 by returning `ar1` instead of `aux`, is there another reason for returning `aux` instead? 



Discussion:
It seems like that would fix this indeed. There may be a simpler way though:

The general return of this function is built as `np.asarray(ar1)[aux == 0]`. Given that `aux` is the return of a call to `np.in1d`, which has an `invert` optional kwarg, that could instead be computed as:

```
aux = in1d(ar1, ar2, assume_unique=True, invert=True)
return np.asarray(ar1)[aux]
```

It may not be obvious, but that will also work without any specific special casing if `ar1` is empty:

```
>>> a = np.array([], dtype=float)
>>> b = np.in1d(a, [1, 2, 3])
array([], dtype=bool)
>>> a[b]
array([], dtype=float64)
```

So we can get rid of the branch on the size of `aux` altogether.

Would you like to send a PR?

Sounds good, yes I'll send a PR


Resolving patch:
diff --git a/numpy/lib/arraysetops.py b/numpy/lib/arraysetops.py
--- a/numpy/lib/arraysetops.py
+++ b/numpy/lib/arraysetops.py
@@ -470,11 +470,9 @@ def setdiff1d(ar1, ar2, assume_unique=False):
     array([1, 2])
 
     """
-    if not assume_unique:
+    if assume_unique:
+        ar1 = np.asarray(ar1).ravel()
+    else:
         ar1 = unique(ar1)
         ar2 = unique(ar2)
-    aux = in1d(ar1, ar2, assume_unique=True)
-    if aux.size == 0:
-        return aux
-    else:
-        return np.asarray(ar1)[aux == 0]
+    return ar1[in1d(ar1, ar2, assume_unique=True, invert=True)]
diff --git a/numpy/ma/extras.py b/numpy/ma/extras.py
--- a/numpy/ma/extras.py
+++ b/numpy/ma/extras.py
@@ -1278,14 +1278,12 @@ def setdiff1d(ar1, ar2, assume_unique=False):
            fill_value = 999999)
 
     """
-    if not assume_unique:
+    if assume_unique:
+        ar1 = ma.asarray(ar1).ravel()
+    else:
         ar1 = unique(ar1)
         ar2 = unique(ar2)
-    aux = in1d(ar1, ar2, assume_unique=True)
-    if aux.size == 0:
-        return aux
-    else:
-        return ma.asarray(ar1)[aux == 0]
+    return ar1[in1d(ar1, ar2, assume_unique=True, invert=True)]
 
 
 #####--------------------------------------------------------------------------


Test patch:
diff --git a/numpy/lib/tests/test_arraysetops.py b/numpy/lib/tests/test_arraysetops.py
--- a/numpy/lib/tests/test_arraysetops.py
+++ b/numpy/lib/tests/test_arraysetops.py
@@ -5,7 +5,7 @@
 
 import numpy as np
 from numpy.testing import (
-    run_module_suite, TestCase, assert_array_equal
+    run_module_suite, TestCase, assert_array_equal, assert_equal
     )
 from numpy.lib.arraysetops import (
     ediff1d, intersect1d, setxor1d, union1d, setdiff1d, unique, in1d
@@ -286,6 +286,8 @@ def test_setdiff1d(self):
         assert_array_equal(c, ec)
 
         assert_array_equal([], setdiff1d([], []))
+        a = np.array((), np.uint32)
+        assert_equal(setdiff1d(a, []).dtype, np.uint32)
 
     def test_setdiff1d_char_array(self):
         a = np.array(['a', 'b', 'c'])
diff --git a/numpy/ma/tests/test_extras.py b/numpy/ma/tests/test_extras.py
--- a/numpy/ma/tests/test_extras.py
+++ b/numpy/ma/tests/test_extras.py
@@ -1109,6 +1109,8 @@ def test_setdiff1d(self):
         a = arange(10)
         b = arange(8)
         assert_equal(setdiff1d(a, b), array([8, 9]))
+        a = array([], np.uint32, mask=[])
+        assert_equal(setdiff1d(a, []).dtype, np.uint32)
 
     def test_setdiff1d_char_array(self):
         # Test setdiff1d_charray