95

So heres my code:

item = [0,1,2,3,4,5,6,7,8,9]
z = []  # list of integers

for item in z:
    if item not in z:
        print item

z contains a list of integers. I want to compare item to z and print out the numbers that are not in z when compared to item.

I can print the elements that are in z when compared not item, but when I try and do the opposite using the code above nothing prints.

Any help?

gdvalderrama
  • 713
  • 1
  • 17
  • 26
Dave
  • 961
  • 1
  • 7
  • 4
  • Does this answer your question? [Get difference between two lists](https://stackoverflow.com/questions/3462143/get-difference-between-two-lists) – Georgy Jul 24 '20 at 17:30

12 Answers12

215

Your code is not doing what I think you think it is doing. The line for item in z: will iterate through z, each time making item equal to one single element of z. The original item list is therefore overwritten before you've done anything with it.

I think you want something like this:

item = [0,1,2,3,4,5,6,7,8,9]

for element in item:
    if element not in z:
        print(element)

But you could easily do this like:

[x for x in item if x not in z]

or (if you don't mind losing duplicates of non-unique elements):

set(item) - set(z)
kame
  • 20,848
  • 33
  • 104
  • 159
ezod
  • 7,261
  • 2
  • 24
  • 34
  • 5
    using `set` would not work correctly if the list checked contains non-unique elements, as `set` would first remove all but one occurrences of the non-unique element from the list. – VDV Dec 02 '16 at 17:06
72
>> items = [1,2,3,4]
>> Z = [3,4,5,6]

>> print list(set(items)-set(Z))
[1, 2]
Antony Hatchkins
  • 31,947
  • 10
  • 111
  • 111
21

Using list comprehension:

print [x for x in item if x not in Z]

or using filter function :

filter(lambda x: x not in Z, item)

Using set in any form may create a bug if the list being checked contains non-unique elements, e.g.:

print item

Out[39]: [0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9]

print Z

Out[40]: [3, 4, 5, 6]

set(item) - set(Z)

Out[41]: {0, 1, 2, 7, 8, 9}

vs list comprehension as above

print [x for x in item if x not in Z]

Out[38]: [0, 1, 1, 2, 7, 8, 9]

or filter function:

filter(lambda x: x not in Z, item)

Out[38]: [0, 1, 1, 2, 7, 8, 9]
VDV
  • 874
  • 9
  • 12
12
list1 = [1,2,3,4]; list2 = [0,3,3,6]

print set(list2) - set(list1)
jspcal
  • 50,847
  • 7
  • 72
  • 76
4

If you run a loop taking items from z, how do you expect them not to be in z? IMHO it would make more sense comparing items from a different list to z.

Doc Brown
  • 19,739
  • 7
  • 52
  • 88
4

No, z is undefined. item contains a list of integers.

I think what you're trying to do is this:

#z defined elsewhere
item = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

for i in item:
  if i not in z: print i

As has been stated in other answers, you may want to try using sets.

ntownsend
  • 7,462
  • 9
  • 38
  • 35
3
>>> item = set([0,1,2,3,4,5,6,7,8,9])
>>> z = set([2,3,4])
>>> print item - z
set([0, 1, 5, 6, 7, 8, 9])
sberry
  • 128,281
  • 18
  • 138
  • 165
3

Your code is a no-op. By the definition of the loop, "item" has to be in Z. A "For ... in" loop in Python means "Loop though the list called 'z', each time you loop, give me the next item in the list, and call it 'item'"

http://docs.python.org/tutorial/controlflow.html#for-statements

I think your confusion arises from the fact that you're using the variable name "item" twice, to mean two different things.

Josh Wright
  • 2,495
  • 16
  • 20
2

Many of the solutions already posted here will not preserve the original ordering of the elements (because sets are unordered) or are inefficient (because linear search in a list is slower than a lookup in a set).

You can make a set of elements to remove upfront, and then use a list comprehension to retain only the elements which aren't in the set:

items = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
z = [3, 4, 5, 6]

set_z = set(z)
result = [e for e in items if e not in set_z]

Then, result contains:

[0, 1, 2, 7, 8, 9]
BrokenBenchmark
  • 18,126
  • 7
  • 21
  • 33
1

You are reassigning item to the values in z as you iterate through z. So the first time in your for loop, item = 0, next item = 1, etc... You are never checking one list against the other.

To do it very explicitly:

>>> item = [0,1,2,3,4,5,6,7,8,9]
>>> z = [0,1,2,3,4,5,6,7]
>>> 
>>> for elem in item:
...   if elem not in z:
...     print elem
... 
8
9
Mark
  • 106,305
  • 20
  • 172
  • 230
1

In the case where item and z are sorted iterators, we can reduce the complexity from O(n^2) to O(n+m) by doing this

def iexclude(sorted_iterator, exclude_sorted_iterator):
    next_val = next(exclude_sorted_iterator)
    for item in sorted_iterator:
        try:
            while next_val < item:
                next_val = next(exclude_sorted_iterator)
                continue
            if item == next_val:
                continue
        except StopIteration:
            pass
        yield item

If the two are iterators, we also have the opportunity to reduce the memory footprint not storing z (exclude_sorted_iterator) as a list.

  • for loop(which is approved answer) big Oh is `O(n)` and your answer have nested loop a while in for loop so complexity is going to increase in your case which is `O(n^2)` – Muhammad Haseeb Khan Mar 10 '17 at 06:11
0

If the lists are sorted and you know the elements of the checking list are in the base list - you can do a more optimal O(n) solution by using two pointers (where n will be the length of the base_list:

base_list = [0, 1, 2, 3, 4, 5, 6, 7, 8]
checking_list = [1, 3, 5]

expected_return = [0, 2, 4, 6, 7, 8]

j = 0
i = 0
elements_not_in_checking_list = []
while i < len(base_list):
    if j < len(checking_list) and base_list[i] == checking_list[j]:
        i += 1
        j += 1
    else:
        elements_not_in_checking_list.append(base_list[i])
        i += 1
vinayman
  • 572
  • 1
  • 5
  • 10