Checking WHAT is missing from a list when comparing it to another list python
<p>I am looking to see what is missing from a list (A) from list (B)</p>

<p>If I have the following list of strings:</p>

<p><code>A = ['4-5', '3-6', '3-3', '9-0']</code> and <code>B = ['4-4', '4-5', '3-3', '6-9', '5-5', '3-2', '6-6', '9-9', '9,0']</code> and want to check what is missing from A that is in list B. </p>

<p>A = [<strong>4-5</strong>,<strong>3-6</strong>,<strong>3-3</strong>, <strong>9-0</strong>] 
B = [4-4, <strong>4-5</strong>, <strong>3-3</strong>, 6-9, 5-5, <strong>3-6</strong>, 3-2, 6-6, 9-9, <strong>9,0</strong>]</p>

<p>so... from the example from above, I would want it to output <code>['4-4', '6-9', '5-5', '3-2', '6-6', '9-9']</code>.</p>

<p>if I sort both the lists, what's the best way of going about it?</p>

<p>Thanks!</p>

<p>I t hought about doing something like:</p>

<pre><code>unique = []
for n in A:
    if n not in B:
        unique.append(B)
print(unique)
</code></pre>

<p>does this work? it's giving me a very odd output of a list in a list of two strings.</p>

<p>In most situations, the best way is to ignore the fact the data is sorted and just do <code>set(B) - set(A)</code>. Or <code>list(set(B) - set(A))</code> if you definitely need a list for the result.</p>

<p>However, that has a moderately large space overhead (approximately the sum of the sizes of the two input lists). Normally this is nothing to worry about, but if the data is very large (uses more than half your available memory) then you might find you need to reduce this. You could first try:</p>

<pre><code>A_set = set(A)
result = [b for b in B if b not in A_set]
</code></pre>

<p>This avoids constructing a set for B or a set for the difference, so the overhead is approximately the size of A.</p>

<p>For your interest, or for situations where resources are very tightly constrained, you might like to know that it's possible to do this with only constant-space overhead supposing that <code>A</code> and <code>B</code> are already sorted (which in your example they are not, but you promise they will be). The trick is to notice that as you look for each element of B in A:</p>

<ul>
<li>you can search through A in order, and stop searching when you find an element no smaller than the one you're looking for. You won't find it after that because A is sorted.</li>
<li>if you found the previous element of B, then you will not find the next one <em>before</em> the place where you found the previous element of B in A, because both lists are sorted.</li>
<li>if you did not find the previous element of B, then you likewise will not find it before the place where you stopped looking.</li>
<li>therefore at each step we can resume searching from where we left off last time.</li>
</ul>

<p>Putting it all together, this means we can make a single simultaneous pass over each of the inputs <code>A</code> and <code>B</code>, and in the process of this single pass decide for each element of <code>B</code> whether or not it is in <code>A</code>. If you're familiar with merge sort (or merging), then be aware that the process is similar to a merge, but the output is different. Not only is the overhead zero, but for advanced uses we don't even need lists, we can do it all in generators so that the input needn't necessarily even all be in memory at once. But sticking with lists to illustrate it:</p>

<pre><code>def find_element(elt, arr, idx):
    while idx &lt; len(arr) and elt &gt; arr[idx]:
        # haven't found it yet
        idx += 1
    # have found the place where it would go, but is it here?
    if idx &lt; len(arr) and elt == arr[idx]:
        # it's here
        return True, idx + 1
    # not found
    return False, idx

a_idx = 0
b_idx = 0
results = []
while a_idx &lt; len(A) and b_idx &lt; len(B):
    found, a_idx = find_element(B[b_idx], A, a_idx)
    if not found:
        results.append(B[b_idx])
    b_idx += 1
# if there's anything left in B to check then it's definitely not in A
results.extend(itertools.islice(B, b_idx, None))
</code></pre>

<p>Finally, we could potentially improve the speed of <code>find_element</code>, for large arrays, using a binary search instead of a linear search. I leave this as an exercise for the reader :-)</p>

python list sorting