Python - Compare two lists in a comprehension - list

I'm trying to understand how comprehensions work.
I would like to loop through two lists, and compare each to find differences.
If one/or-more word(s) is different, I would like to print this word(s).
I'd like this all in one nice line of code, which is why I'm interested in comprehensions.

Doing it in "one nice line of code" is code golf, and misguided. Make it readable instead.
for a, b in zip(list1, list2):
if a != b:
print(a, "is different from", b)
This is not different in any significant way from this:
[print(a, "is different from", b) for a, b in zip(list1, list2) if a!=b]
Except that the expanded version easier to read and understand than the comprehension.

Like kriegar suggested using sets is probably the easiest solution. If you absolutely need to use list comprehension, I'd use something like this:
list_1 = [1, 2, 3, 4, 5, 6]
list_2 = [1, 2, 3, 0, 5, 6]
# Print all items from list_1 that are not in list_2 ()
print(*[item for item in list_1 if item not in list_2], sep='\n')
# Print all items from list_1 that differ from the item at the same index in list_2
print(*[x for x, y in zip(list_1, list_2) if x != y], sep='\n')
# Print all items from list_2 that differ from the item at the same index in list_1
print(*[y for x, y in zip(list_1, list_2) if x != y], sep='\n')

If you want to compare two lists for differences, I think you want to use a set.
s.symmetric_difference(t) s ^ t new set with elements in either s or t but not both
example:
>>> L1 = ['a', 'b', 'c', 'd']
>>> L2 = ['b', 'c', 'd', 'e']
>>> S1 = set(L1)
>>> S2 = set(L2)
>>> difference = list(S1.symmetric_difference(S2))
>>> print difference
['a', 'e']
>>>
one-line form?
>>> print list(set(L1).symmetric_difference(set(L2)))
['a', 'e']
>>>
if you really want to use a list comprehension:
>>> [word for word in L1 if word not in L2] + [word for word in L2 if word not in L1]
['a', 'e']
much less efficient as the size of the lists grow.

Related

How to match elements from arrays and only print matches?

I have two lists, i am trying to match one item from the first list to another from the second list under a certain condition (for example if they share the same number in the same location). i wrote my code to match the first set ['A','B','C',4,'D'] and only print the set from list2 that has 4 in the same location. so basically my output would be:
['A','B','C',4,'D']
[1, 2, 3, 4, 5]
well i can't figure out how to print only the match
here is my code:
list1 = [['A','B','C',4,'D'],['A','B','C',9,'D'],['A','B','C',5,'D'],['A','B','C',6,'D'],['A','B','C',7,'D']]
list2 = [[1,2,3,2,5],[1,2,3,5,5],[1,2,3,3,5],[1,2,3,4,5],[1,2,3,1,5],[1,2,3,2,5]]
for var in list1:
print var
for i in range(0,len(list2)):
for var1 in list2:
if list1[0][3] == list2[i][3]:
print var1
Your program would become easier, if you used izip of itertools. Assuming you just need to print the elements
from itertools import izip
list1 = [['A','B','C',4,'D'],['A','B','C',9,'D'],['A','B','C',5,'D'],['A','B','C',6,'D'],['A','B','C',7,'D']]
list2 = [[1,2,3,2,5],[1,2,3,5,5],[1,2,3,3,5],[1,2,3,4,5],[1,2,3,1,5],[1,2,3,2,5]]
for item1 in list1:
for item2 in list2:
for i,j in izip(item1, item2):
if i==j:
print i
By using izip two times, it would be much easier
from itertools import izip
list1 = [['A','B','C',4,'D'],['A','B','C',9,'D'],['A','B','C',5,'D'],['A','B','C',6,'D'],['A','B','C',7,'D']]
list2 = [[1,2,3,2,5],[1,2,3,5,5],[1,2,3,3,5],[1,2,3,4,5],[1,2,3,1,5],[1,2,3,2,5]]
for i in izip(list1,list2):
for item1, item2 in izip(i[0],i[1]):
if item1 == item2:
print item1
Almost. I am not sure if that is what you wanted but the following code prints all pairs which have the same number in the 4th location of the array:
list1 = [['A','B','C',4,'D'],['A','B','C',9,'D'],['A','B','C',5,'D'],
['A','B','C',6,'D'],['A','B','C',7,'D']]
list2 = [[1,2,3,2,5],[1,2,3,5,5],[1,2,3,3,5],[1,2,3,4,5],[1,2,3,1,5],
[1,2,3,2,5]]
for t in list1:
print t
for b in list2:
if t[3] == b[3]:
print b
Output is:
['A', 'B', 'C', 4, 'D']
[1, 2, 3, 4, 5]
['A', 'B', 'C', 9, 'D']
['A', 'B', 'C', 5, 'D']
[1, 2, 3, 5, 5]
['A', 'B', 'C', 6, 'D']
['A', 'B', 'C', 7, 'D']
Is that what you were looking for?

Find unique items in a list using a passed value for range of the list (sublists)

I am trying to tie two different things together.
1. Find and print unique items in a list.
2. Pass a int value and print unique items in the first n items
I have two things that work, but not in conjunction, to split the list into sub-lists of n:
def find_uniques(3):
lista = ['a', 'a', 'b','c','d','c','e','d','e','f','f']
lists = [lista[x:x+n] for x in xrange(0, len(lista), n)]
print lists
[['a', 'a', 'b'], ['c', 'd', 'c'], ['e', 'd', 'e'], ['f', 'f']]
# 2nd part works on the whole list
print [a for a in lista if lista.count(a) == 1]
['b']
# How do I get the second part to work on the sub lists, and give me back unique chars from each sub list.
The output I am looking for:
[['b'],['d'], ['d']]
Usually it is easier to just split out these operations instead of merging, but here is a nested list comprehension.
lista = ['a', 'a', 'b','c','d','c','e','d','e','f','f']
n = 3
[[ item for item in sublist if sublist.count(item) == 1] for sublist in [ lista[x:x+n] for x in xrange(0, len(lista), n) ] ]
Personally, although it is longer, I prefer a more readable version like so:
def findunique(lista,n=3):
listoflists = [ lista[x:x+n] for x in xrange(0,len(lista),n) ]
results = []
for sublist in listoflists:
unique = [ item for item in sublist if sublist.count(item) == 1]
if unique:
results.append(unique)
return results
lista = ['a','a','b','c','d','c','e','d','e','f','f']
print findunique(lista,3)

Finding a key in a dictionary which appears first in a list

I have a list and a dictionary as below:
List1 = ['a', 'b', 'c', 'd']
d1 = OrderedDict([('c', '1'), ('b', '2')])
Suppose, List1 is a sorted list. How do I find a key in d1 which appears first in the List1? In example above its 'b'.
My code is below-
print d1.items()
d2={}
for key in d1:
d2 [key]=List1.index(key)
print "Output is", min(d2.items(), key=lambda x: x[1])[0]
The code is verbose. I would prefer more efficient code, may be one line code.
Edit: All keys of the dictionary appear on the list.
On average, x in set is O(1) while x in list is O(n).
In [17]: List1 = ['a', 'b', 'c', 'd']
In [18]: d1 = OrderedDict([('c', '1'), ('b', '2')])
In [19]: for key in List1:
....: if key in d1:
....: print key
....: break
....:
b
If you only want to have the top-first, then the code Sait posted does it. If you want to get all the keys that are found in the dict in the sequence they are found in the list the following helps. And in addition the first element of the returned list is of course the first found.
from collections import OrderedDict
List1 = ['a', 'b', 'c', 'd']
d1 = OrderedDict([('c', '1'), ('b', '2')])
found = [el for el in List1 if el in d1]

How do you merge indexes of two lists in Groovy?

I have two lists that I need to merge into a new list, but the new list needs to contain merged indexes of the original lists. For example:
List1 = [1, 2, 3]
List2 = [a, b, c]
I need the output to be:
finalList = [1a, 2b, 3c]
I need to be able to do this in groovy. I appreciate any help you can provide.
Assuming both lists are the same size, in Groovy 2.4+,
list1 = [1, 2, 3]
list2 = ['a', 'b', 'c']
assert ['1a', '2b', '3c'] == list1.withIndex().collect { it, index -> it + list2[index] }
Alternatively and a bit more simply in Groovy 1.5+,
assert ['1a', '2b', '3c'] == [list1, list2].transpose()*.sum()
The following is very close to doelleri's solution:
In Groovy 2.4+
println ([list1, list2].transpose().collect{it -> it[0] + it[1]})
OUTPUT
[1a, 2b, 3c]

How to check if all of the following items are in a list?

I found, that there is related question, about how to find if at least one item exists in a list:
How to check if one of the following items is in a list?
But what is the best and pythonic way to find whether all items exists in a list?
Searching through the docs I found this solution:
>>> l = ['a', 'b', 'c']
>>> set(['a', 'b']) <= set(l)
True
>>> set(['a', 'x']) <= set(l)
False
Other solution would be this:
>>> l = ['a', 'b', 'c']
>>> all(x in l for x in ['a', 'b'])
True
>>> all(x in l for x in ['a', 'x'])
False
But here you must do more typing.
Is there any other solutions?
Operators like <= in Python are generally not overriden to mean something significantly different than "less than or equal to". It's unusual for the standard library does this--it smells like legacy API to me.
Use the equivalent and more clearly-named method, set.issubset. Note that you don't need to convert the argument to a set; it'll do that for you if needed.
set(['a', 'b']).issubset(['a', 'b', 'c'])
I would probably use set in the following manner :
set(l).issuperset(set(['a','b']))
or the other way round :
set(['a','b']).issubset(set(l))
I find it a bit more readable, but it may be over-kill. Sets are particularly useful to compute union/intersection/differences between collections, but it may not be the best option in this situation ...
I like these two because they seem the most logical, the latter being shorter and probably fastest (shown here using set literal syntax which has been backported to Python 2.7):
all(x in {'a', 'b', 'c'} for x in ['a', 'b'])
# or
{'a', 'b'}.issubset({'a', 'b', 'c'})
What if your lists contain duplicates like this:
v1 = ['s', 'h', 'e', 'e', 'p']
v2 = ['s', 's', 'h']
Sets do not contain duplicates. So, the following line returns True.
set(v2).issubset(v1)
To count for duplicates, you can use the code:
v1 = sorted(v1)
v2 = sorted(v2)
def is_subseq(v2, v1):
"""Check whether v2 is a subsequence of v1."""
it = iter(v1)
return all(c in it for c in v2)
So, the following line returns False.
is_subseq(v2, v1)
Not OP's case, but - for anyone who wants to assert intersection in dicts and ended up here due to poor googling (e.g. me) - you need to work with dict.items:
>>> a = {'key': 'value'}
>>> b = {'key': 'value', 'extra_key': 'extra_value'}
>>> all(item in a.items() for item in b.items())
True
>>> all(item in b.items() for item in a.items())
False
That's because dict.items returns tuples of key/value pairs, and much like any object in Python, they're interchangeably comparable
Another solution would be:
l = ['a', 'b', 'c']
potential_subset1 = ['a', 'b']
potential_subset2 = ['a', 'x']
print(False not in [i in l for i in potential_subset1]) # True
print(False not in [i in l for i in potential_subset2]) # False
What makes my solution great is that you can write one-liners by putting the lists inline.
An example of how to do this using a lambda expression would be:
issublist = lambda x, y: 0 in [_ in x for _ in y]
Short syntax
I discovered a very readable syntax while experimenting on the Python interpreter.
>>> my_list = [1, 2, 3, 4, 5]
>>> (6 or 7) in my_list
False
>>> (2 or 6) in my_list
True
>>> (2 and 6) in my_list
False
>>> (2 and 5) in my_list
True
List of items to search for
If you have a long list of objects to search for, held in a sub_list variable:
>>> my_list = [1, 2, 3, 4, 5]
>>> sub_list = ['x', 'y']
If any (at least one) item is contained in the superset (or statement):
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
False
>>> sub_list[0] = 3
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
True
If all items are contained in superset (and statement), then sub_list is a full subset. Also featuring a bit of De Morgan's Law:
>>> next((False for item in sub_list if item not in my_list), True)
False
>>> sub_list[1] = 2
>>> next((False for item in sub_list if item not in my_list), True)
True
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
True