简体   繁体   中英

Python: List of tuples: compare all tuples and retrive tuples where the elements of tuples are not equal to any other tuple

I have a list of tuples like so:

z = [(408, 2, 5), (408, 2, 2), (181, 2, 2), (181, 2, 5), (907, 2, 6), (907, 2, 1), (276, 2, 5), (276, 2, 2), (100, 2, 1), (100, 2, 6), (408, 3, 5), (408, 3, 2), (181, 3, 2), (181, 3, 5), (907, 3, 6), (907, 3, 1), (276, 3, 5), (276, 3, 2), (100, 3, 6), (100, 3, 1), (907, 10, 6), (907, 10, 1), (100, 10, 1), (100, 10, 6), (907, 11, 6), (907, 11, 1), (100, 11, 6), (100, 11, 1)]

What I am looking to do is compare all the tuples to one another and return the tuples for which each element in tuple is unique to all other tuples.

in the list above the first element of any tuple can have the values 408, 181, 907, 276 or 100 the second element has values 2, 3, 10 or 11 and the third element values 1, 2, 5 or 6 .

The output of querying the list would return four tuples as element two (and indeed element 3) of the tuple has a maximum of four possibilities. Example output:

[(408, 2, 5), (181, 3, 2), (907, 10, 6), (100, 11, 1)]

I have tried using while loops and stepping through each element of the list and tuple respectively to delete the respective element of the list or create a separate list but this approach does not consider all possibility's and feels wrong:

i = 0
j = 1
try:
    while i < len(z):
        if z[i][0] == z[j][0] or z[i][1] == z[j][1] or z[i][2] == z[j][2]:
            del z[j]
        else:
            j += 1
            i += 1
except:
    pass

I have also looked into sets but from what I gather it would only delete duplicates of tuples.

Thanks.

This one-liner could do it, provided you want tuples with unique values, not tuples that correspond to one of the actual input tuples (since you state "... return the tuples for which each element in tuple is unique to all other tuples.").

>>> list(zip(*(set(zz) for zz in zip(*z))))
[(408, 2, 1), (907, 3, 2), (276, 10, 5), (181, 11, 6)]

While fun, I can hardly recommend this for obvious reasons.


Explanation of what happens:

zip(*z)

This "inverts" the list of tuples, so going from 28 x 3, this is 3 * 28.

(set(zz) for zz in zip(*z))

Filter the unique values in each len-28 tuple. This results in:

[{408, 907, 276, 181, 100}, {2, 3, 10, 11}, {1, 2, 5, 6}]

Now we need to create tuples from this. We can use zip again:

zip(*(set(zz) for zz in zip(*z)))

and luckily, zip stops when the first element is exhausted, that is, a 4-len tuple; it doesn't require all tuples to be of length 5.

You can compare all tuples using a double loop, and use list comprehension for scalability:

i = 0
while i < len(z):
    j = i+1
    while j < len(z):
        if any([z[i][n]==z[j][n] for n in range(len(z[0]))]):
            del z[j] # Shift all values, so no need to update j
        else:
            j += 1
    i += 1

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