Ignacio Garcia
Ignacio Garcia

Reputation: 73

How to check if elements on two lists are the same (with order changed)

I´m working on python and I basically have a lists with different elements. If I print some of the elements it looks like the following:

print('%s'%list[0])
print('%s'%list[1])

Output:
[('A', 'B'), ('D', 'E'), ('B', 'Z'), ('Z', 'D')]
[('B', 'M'), ('M', 'R'), ('B', 'A'), ('R', 'Z'), ('H', 'M')]

I want to check if one of the elements is repeated in both lists. But it can be repeated in a different order. For example, the element ('A', 'B') IS repeated but with a different order ('B', 'A') in the second list.

I want to compare list[0][0] (that is ('A', 'B')) with all of the elements of list[1] and obtain true for element list[0][2].

How could I do this??

Thanks

Upvotes: 1

Views: 106

Answers (4)

Matt P
Matt P

Reputation: 2367

You can use the set.intersection method to return any shared elements from two (or more) sets. In the example below, each list of tuples is first converted to a set of sets. Note that each tuple is mapped to a frozenset so it remains hashable. The function then returns a list of any shared items. Just to remain consistent with the original input object type, each item in the return list is converted back into a tuple.

def listSharedItems( list1, list2 ):
    list1_sets = set(map(frozenset,list1))
    list2_sets = set(map(frozenset,list2))
    intersect  = list1_sets.intersection(list2_sets)
    return map(tuple,intersect)

>>> # Example usage:
>>> alist = [[('A','B'), ('D','E'), ('B','Z'), ('Z','D')], 
             [('B','M'), ('M','R'), ('B','A'), ('R','Z'), ('H','M')]]
>>> listSharedItems( alist[0], alist[1] )
>>> [('A', 'B')]

Upvotes: 0

moritzg
moritzg

Reputation: 4394

You can use two for-loops to obtain true if the elements match, by converting them to sets (because sets don't have an order):

l1 = [('A', 'B'), ('D', 'E'), ('B', 'Z'), ('Z', 'D')]
l2 = [('B', 'M'), ('M', 'R'), ('B', 'A'), ('R', 'Z'), ('H', 'M')]

elementToCompare = set(l1[0])

for i in l2:
    if elementToCompare == set(i):
        print("%s is the same as %s"%(l1[0], i))

Output:

('A', 'B') is the same as ('B', 'A')

Upvotes: 0

hiro protagonist
hiro protagonist

Reputation: 46921

you can turn your tuples into sets; that way the order will not matter:

a = [('A', 'B'), ('D', 'E'), ('B', 'Z'), ('Z', 'D')]
b = [('B', 'M'), ('M', 'R'), ('B', 'A'), ('R', 'Z'), ('H', 'M')]

a_set = list(set(item) for item in a)
b_set = list(set(item) for item in b)

# create a list of items that are in a and b:
res = [item for item in a_set if item in b_set]
print(res)  # [{'A', 'B'}]

if speed is an issue you could even to this:

a_set = set(frozenset(item) for item in a)
b_set = set(frozenset(item) for item in b)

res = a_set & b_set
# {frozenset({'A', 'B'})}

this could then easily be converted back to a list containing tuples with res = [tuple(item) for item in res].

note that duplicates will be treated as single entries in the last version.

Upvotes: 2

tobias_k
tobias_k

Reputation: 82949

In case the elements can contain some items multiple times, and set does thus not work, you could also use sorted to normalize the order within the elements.

>>> a = [('A', 'B'), ('D', 'E'), ('B', 'Z'), ('Z', 'D')]
>>> b = [('B', 'M'), ('M', 'R'), ('B', 'A'), ('R', 'Z'), ('H', 'M')]
>>> b_set = set([tuple(sorted(x)) for x in b])
>>> [x for x in [tuple(sorted(y)) for y in a] if x in b_set]
[('A', 'B')]

Note that if you want to use a set to make the lookup faster, you have to wrap the sorted elements into tuples so they are hashable.

Upvotes: 1

Related Questions