Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding matching and nonmatching items in lists

Tags:

python

I'm pretty new to Python and am getting a little confused as to what you can and can't do with lists. I have two lists that I want to compare and return matching and nonmatching elements in a binary format. List1 is of constant length, while the length of List2 differs (but is always shorter than List1).

For example:

List1 = ['dog', 'cat', 'pig', 'donkey']
List2 = ['dog', 'cat', 'donkey']

Output wanted:

List3 = [1, 1, 0, 1]

The code I have so far is:

def match_nonmatch(List1, List2):
    List3 = []
    for i in range(len(List1)):
        for j in range(len(List2)):
            if List1[i] == List2[j]:
                List3.append(1)
            else:
                List3.append(0)
   return List3

I am able to return the matches when I compare the lists, but when I include the else statement shown above to return the nonmatches I end up with a list that is way longer than it should be. For instance, when I use a list comparing 60 items, I get a list that contains 3600 items rather than 60.

I'd appreciate it if someone could explain to me the problem with my code as it currently stands and suggest how I could modify the code so it does what I want.

like image 328
Platypus Avatar asked Jan 22 '12 11:01

Platypus


4 Answers

Use set instead of list. This way you can do lots of nice things:

set1 = set(['dog', 'cat', 'pig', 'donkey'])
set2 = set(['dog', 'cat', 'donkey'])

matched = set1.intersection(set2) # set(['dog', 'cat', 'donkey'])
unmatched = set1.symmetric_difference(set2) # set(['pig'])

I know it's not exactly what you asked for, but it's usually a better practice to use sets instead of lists when doing this sort of things.

More on sets here: http://docs.python.org/library/stdtypes.html#set

like image 186
Dor Shemer Avatar answered Nov 16 '22 01:11

Dor Shemer


use the following code.

listt3=[]

for i in listt1:
    if i in listt2:
        listt3.append(1)
    else:
        listt3.append(0)

If you prefer one-liners,

listt3=[ 1 if i in listt2 else 0 for i in listt1]

like image 43
Srinivas Reddy Thatiparthy Avatar answered Nov 16 '22 02:11

Srinivas Reddy Thatiparthy


You can use bitwise operation too:

List1 = ['dog', 'cat', 'pig', 'donkey']  
List2 = ['dog', 'cat', 'donkey']  

matching:

set(List1) & set(List2)   

not matching:

set(List1) ^ set(List2) 
like image 41
Mahdi Shahbaba Avatar answered Nov 16 '22 01:11

Mahdi Shahbaba


Here is how I would do it if list2 is short:

list1 = ['dog', 'cat', 'pig', 'donkey']
list2 = ['dog', 'cat', 'donkey']
list3 = [int(val in list2) for val in list1]
print(list3)

This prints:

[1, 1, 0, 1]

If list2 is long, you could convert it to a set first to make the code more efficient:

list1 = ['dog', 'cat', 'pig', 'donkey']
set2 = set(['dog', 'cat', 'donkey'])
list3 = [int(val in set2) for val in list1]
print(list3)

The reason your current code produces too many elements is that you call append() on every iteration of the inner loop, and there are len(List1) * len(List2) such iterations.

Here is how it can be fixed:

def match_nonmatch(List1, List2):
    List3 = []
    for i in range(len(List1)):
        for j in range(len(List2)):
            if List1[i] == List2[j]:
                List3.append(1)
                break             # fix #1
        else:                     # fix #2
            List3.append(0)
    return List3

Note the added break and the fact that the else clause is now refers to the inner for and not the if.

That said, I'd still use the one-liner at the top of my answer.

like image 26
NPE Avatar answered Nov 16 '22 03:11

NPE