简体   繁体   中英

Find overlapping elements in a list of tuples?

From my understanding of the intersection function, it finds complete overlap between elements in a list. For example:

tup_1 = [(1,2,3),(4,5,6)]
tup_2 = [(4,5,6)]
ol_tup = set(tup_1).intersection(tup_2)
print ol_tup

would yield:

set([(4, 5, 6)])

However, suppose my list of tuples are set up as this:

tup_1 = [(1,2,3),(4,5,5)]
tup_2 = [(4,5,6)]

Where there's an overlap in 2 elements of the 2nd tuple in tup_1 and 1st tuple in tup_2. If I want to python to return these 2 tuples: (4,5,5) and (4,5,6), is there an easier way than this nested for loop (below)?

for single_tuple_1 in tup_1:
    for single_tuple_2 in tup_2:
        if single_tuple_1[0] == single_tuple_2[0] and single_tuple_1[1] == single_tuple_2[1]:
            print single_tuple_1,single_tuple_2

EDIT:

For this case, suppose order matters and suppose the tuples contain 5 elements:

tup_1 = [(1,2,3,4,5),(4,5,6,7,8),(11,12,13,14,15)]
tup_2 = [(1,2,3,4,8),(4,5,1,7,8),(11,12,13,14,-5)]

And I would like to find the tuples that intersect with each other in their respective first 4 elements. So the result should be:

[(1,2,3,4,5),(1,2,3,4,8),(11,12,13,14,15),(11,12,13,14,-5)]

How would the code change to accommodate this?

If you want to return all the pairs of "overlapping" tuples there's no way around comparing all the pairs, ie a quadratic algorithm. But you could make the code a bit more elegant using a list comprehension, product for the combinations and zip and sum for the comparison:

>>> tup_1 = [(1,2,3),(4,5,5),(7,8,9)]

>>> tup_2 = [(4,5,6),(0,5,5),(9,8,7)]

>>> [(a, b) for (a, b) in itertools.product(tup_1, tup_2)
...         if sum(1 for ai, bi in zip(a, b) if ai == bi) >= 2]
[((4, 5, 5), (4, 5, 6)), ((4, 5, 5), (0, 5, 5))]

Note: This checks whether two tuples have the same element in at least two positions, ie order matters. If order should not matter, you can convert a and b to set instead and check the size of their intersection, but that might fail for repeated numbers, ie the intersection of (1,1,2) and (1,1,3) would just be 1 instead of 2 .

If you only want to match the first two, or first two and last two elements, you can compare slices of the tuples in an accordant disjunction:

>>> [(a, b) for (a, b) in itertools.product(tup_1, tup_2)
...         if a[:2] == b[:2]]
[((4, 5, 5), (4, 5, 6))]

>>> [(a, b) for (a, b) in itertools.product(tup_1, tup_2)
...         if a[:2] == b[:2] or a[-2:] == b[-2:]]
[((4, 5, 5), (4, 5, 6)), ((4, 5, 5), (0, 5, 5))]

This is one way using a list comprehension. The logic as written checks for an overlap of at least 2 elements.

Note that if there is no overlap you will be left with the one element of tup_2 , but that can be trivially identified.

from itertools import chain

tup_1 = [(1,2,3),(4,5,5)]
tup_2 = [(4,5,6)]

y = sorted(tup_2[0])
res = [i for i in chain(tup_1, tup_2) if
       sum(i==j for i, j in zip(sorted(i), y)) > 1]

print res

[(4, 5, 5), (4, 5, 6)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM