Oblomov
Oblomov

Reputation: 9635

Sort out pairs with same members but different order from list of pairs

From the list

l =[(3,4),(2,3),(4,3),(3,2)]

I want to sort out all second appearances of pairs with the same members in reverse order. I.e., the result should be

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

What's the most concise way to do that in Python?

Upvotes: 1

Views: 99

Answers (4)

Guillaume
Guillaume

Reputation: 6009

IMHO, this should be both shorter and clearer than anything posted so far:

my_tuple_list = [(3,4),(2,3),(4,3),(3,2)]

set((left, right) if left < right else (right, left) for left, right in my_tuple_list)

>>> {(2, 3), (3, 4)}

It simply makes a set of all tuples, whose members are exchanged beforehand if first member is > second member.

Upvotes: 0

Thierry Lathuille
Thierry Lathuille

Reputation: 24232

If we want to keep only the first tuple of each pair:

l =[(3,4),(2,3),(4,3),(3,2), (3, 3), (5, 6)]

def first_tuples(l):
    # We could use a list to keep track of the already seen
    # tuples, but checking if they are in a set is faster
    already_seen = set()
    out = []
    for tup in l:
        if set(tup) not in already_seen:
            out.append(tup)
            # As sets can only contain hashables, we use a 
            # frozenset here
            already_seen.add(frozenset(tup))
    return out

print(first_tuples(l))
# [(3, 4), (2, 3), (3, 3), (5, 6)]

Upvotes: 1

boot-scootin
boot-scootin

Reputation: 12515

This ought to do the trick:

[x for i, x in enumerate(l) if any(y[::-1] == x for y in l[i:])]
Out[23]: [(3, 4), (2, 3)]

Expanding the initial list a little bit with different orderings:

l =[(3,4),(2,3),(4,3),(3,2), (1,3), (3,1)]

[x for i, x in enumerate(l) if any(y[::-1] == x for y in l[i:])]
Out[25]: [(3, 4), (2, 3), (1, 3)]

And, depending on whether each tuple is guaranteed to have an accompanying "sister" reversed tuple, the logic may change in order to keep "singleton" tuples:

l = [(3, 4), (2, 3), (4, 3), (3, 2), (1, 3), (3, 1), (10, 11), (10, 12)]

[x for i, x in enumerate(l) if any(y[::-1] == x for y in l[i:]) or not any(y[::-1] == x for y in l)]
Out[35]: [(3, 4), (2, 3), (1, 3), (10, 11), (10, 12)]

Upvotes: 0

ewcz
ewcz

Reputation: 13087

Alternatively, one might do it in a more verbose way:

l = [(3,4),(2,3),(4,3),(3,2)]
L = []
omega = set([])
for a,b in l:
    key = (min(a,b), max(a,b))
    if key in omega:
        continue
    omega.add(key)
    L.append((a,b))

print(L)

Upvotes: 1

Related Questions