Argh. I could swear that yesterday I typed test cases just like the
one you provide, and it behaved correctly. Nevertheless, it clearly
fails in spite of my memory, so attached is a version which I believe
gives the correct behavior.
Greg
On Tue, Aug 5, 2008 at 9:00 AM, Robert Cimrman <[EMAIL PROTECTED]> wrote:
> I do not have much time to investigate it in detail right now, but it
> does not work for repeated entries in ar1:
>
> In [14]: nm.setmember1d( [1,2,3,2], [1, 3] )
> Out[14]: array([ True, True, True, False], dtype=bool)
def setmember1d( ar1, ar2, handle_dupes=True):
"""Return a boolean array of shape of ar1 containing True where the elements
of ar1 are in ar2 and False otherwise.
If handle_dupes is true, allow for the possibility that ar1 or ar2
each contain duplicate values. If you are sure that each array
contains only unique elelemnts, you can set handle_dupes to False
for faster execution.
Use unique1d() to generate arrays with only unique elements to use as inputs
to this function.
:Parameters:
- `ar1` : array
- `ar2` : array
- `handle_dupes` : boolean
:Returns:
- `mask` : bool array
The values ar1[mask] are in ar2.
:See also:
numpy.lib.arraysetops has a number of other functions for performing set
operations on arrays.
"""
# We need this to be a stable sort, so always use 'mergesort' here. The
# values from the first array should always come before the values from the
# second array.
ar = nm.concatenate( (ar1, ar2 ) )
order = ar.argsort(kind='mergesort')
sar = ar[order]
equal_adj = (sar[1:] == sar[:-1])
flag = nm.concatenate( (equal_adj, [False] ) )
if handle_dupes:
# if there is duplication, then being equal to your next
# higher neighbor in the sorted array equal is not sufficient
# to establish that your value exists in ar2 -- it may have
# come from ar1. A complication is that that this is
# transitive: setmember1d([2,2], [2]) must recognize _both_
# 2's in ar1 as appearing in ar2, so neither is it sufficient
# to test if you're equal to your neighbor and your neighbor
# came from ar2. Initially mask is 0 for values from ar1 and
# 1 for values from ar2. If an entry is equal to the next
# higher neighbor and mask is 1 for the higher neighbor, then
# mask is set to 1 for the lower neighbor also. At the end,
# mask is 1 if the value of the entry appears in ar2.
zlike = nm.zeros_like
mask = nm.concatenate( (zlike( ar1 ), zlike( ar2 ) + 1) )
smask = mask[order]
prev_smask = zlike(smask) - 1
while not (prev_smask == smask).all():
prev_smask[:] = smask
smask[nm.where(equal_adj & smask[1:])[0]] = 1
flag *= smask
indx = order.argsort(kind='mergesort')[:len( ar1 )]
return flag[indx]
_______________________________________________
Numpy-discussion mailing list
[email protected]
http://projects.scipy.org/mailman/listinfo/numpy-discussion