-1

The trouble I'm having is that these tuples are inside a list of lists of lists as shown below:

giantlist = [[[(0,2), (2,3), (4,5)],[(0,2), (3,4), (6,8)], [(3,4),(0,2)]]]

So, my issue is trying to traverse through each list and find out if they have tuples in common which I then like to print "found common points between list 1 and list 2".

For example: The first list inside the list of lists of lists is

[(0,2),(2,3),(4,5)]

and it has a common tuple with the second list which is the point [(0,2)]

The third list which is shown below also has the common point [(0,2)]

[(3,4),(0,2)]

I would then like to print list1 has a common point with list2 and list3

I've tried a lot of different loops but I'm having trouble comparing the lists because I cant index them properly. I figured that I could find the intersection between these lists and if they had an intersection then I would print.

I also found that maybe I could get the length of each list and then union them and check if the union length is less than the length of the two lists together, that would mean they have a common tuple.

divibisan
  • 11,659
  • 11
  • 40
  • 58
jakebrah
  • 37
  • 2
  • 2
    You're talking about "intersection" and "union" and so on, so… is there a reason you're using lists instead of sets here? (In fact, even if these things need to be list for a _different_ part of your code, copying them into sets to write _this_ part could still be a great idea, making it easy to understand and maybe even being the CPU-fastest solution to boot.) – abarnert Mar 08 '18 at 19:40

2 Answers2

3

The easiest way to see if two lists have any intersection is to turn them into sets and just use the intersection method or & operator:

>>> lst1 = [(0,2),(2,3),(4,5)]
>>> lst2 = [(3,4),(0,2)]
>>> set(lst1) & set(lst2)
{(0, 2)}

If efficiency (space or speed) is an issue, you may want to convert only the smaller one to a set:

>>> set(lst1).intersection(lst2) if len(lst1) > len(lst2) else set(lst2).intersection(lst1)

But really, that's as complicated as you probably need to get.

Of course this doesn't solve your entire assignment, just the part you're stuck on. You still need to figure out how to apply this to every pair of lists (or what you can do that's more efficient than applying it to every pair of lists).

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Thank you, and yes I'm still trying to find a way to apply this to every list but cant seem to find way to loop through each list properly. – jakebrah Mar 08 '18 at 20:17
  • 1
    @jakebrah Well, the simple way is just loop over the same list twice, nested; something like: `for i, a in enumerate(big_list): for j, b in enumerate(big_list): if set(a) & set(b): print(f'list {a} and list {b} have a common post')`. This will give you some duplication (you'll see "list 1 and list 3" and later "list 3 and list 1"), and there's a more efficient algorithm, but you should be able to code this up first. If you get stuck, create a new question with what you've done and where you're stuck. – abarnert Mar 08 '18 at 20:23
1

There are existing tools for this. You can, for example, use collections.Counter for an O(n) solution and combine it with @hexparrot's flattener function:

from collections import Counter

giantlist = [[[(0,2), (2,3), (4,5)],[(0,2), (3,4), (6,8)], [(3,4),(0,2)]]]

def flatten(container):
    for i in container:
        if isinstance(i, list):
            for j in flatten(i):
                yield j
        else:
            yield i

c = Counter(flatten(giantlist))

Result is a dictionary mapping each tuple to its count:

Counter({(0, 2): 3, (3, 4): 2, (2, 3): 1, (4, 5): 1, (6, 8): 1})

You can adapt the above solution for comparing between specific lists, possibly via itertools.combinations.

jpp
  • 159,742
  • 34
  • 281
  • 339