How to check if an array contains all the elements of another array? If not, output the missing elements

Viewed 1487

I need to check if an array A contains all elements of another array B. If not, output the missing elements. Both A and B are integers, and B is always from 0 to N with an interval of 1.

import numpy as np
A=np.array([1,2,3,6,7,8,9])
B=np.arange(10)

I know that I can use the following to check if there is any missing elements, but it does not give the index of the missing element.

np.all(elem in A  for elem in B)

Is there a good way in python to output the indices of the missing elements?

3 Answers

IIUC you can try the following and assuming that B always is an "index" list:

[i for i in B if i not in A]

The output would be : [0, 4, 5]

Best way to do it with numpy

Numpy actually has a function to perform this : numpy.insetdiff1d

np.setdiff1d(B, A)

# Which returns
array([0, 4, 5])

You can use enumerate to get both index and content of a list. The following code would do what you want

    idx = [idx for idx, element in enumerate(B) if element not in A]

I am assuming we want to get the elements exclusive to B, when compared to A.

Approach #1

Given the specific of B is always from 0 to N with an interval of 1, we can use a simple mask-based one -

mask = np.ones(len(B), dtype=bool)
mask[A] = False
out = B[mask]

Approach #2

Another one that edits B and would be more memory-efficient -

B[A] = -1
out = B[B>=0]

Approach #3

A more generic case of integers could be handled differently -

def setdiff_for_ints(B, A):
    N = max(B.max(), A.max()) - min(min(A.min(),B.min()),0) + 1
    mask = np.zeros(N, dtype=bool)
    mask[B] = True
    mask[A] = False
    out = np.flatnonzero(mask)
    return out

Sample run -

In [77]: A
Out[77]: array([ 1,  2,  3,  6,  7,  8, -6])

In [78]: B
Out[78]: array([1, 3, 4, 5, 7, 9])

In [79]: setdiff_for_ints(B, A)
Out[79]: array([4, 5, 9])

# Using np.setdiff1d to verify :
In [80]: np.setdiff1d(B, A)
Out[80]: array([4, 5, 9])

Timings -

In [81]: np.random.seed(0)
    ...: A = np.unique(np.random.randint(-10000,100000,1000000))
    ...: B = np.unique(np.random.randint(0,100000,1000000))

# @Hugolmn's soln with np.setdiff1d
In [82]: %timeit np.setdiff1d(B, A)
4.78 ms ± 96.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [83]: %timeit setdiff_for_ints(B, A)
599 µs ± 6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Related