MK.
MK.

Reputation: 4027

filtering a list of tuples in python

Am looking for a clean pythonic way of doing the following

I have a list of tuples say :

[(1,'a'), (1,'b'), (1,'c'), (2, 'd'), (5, 'e'), (5, 'f')]

I want to make a new list which discards tuples whose first key has been seen before. So the o/p for the above would be:

[(1,'c'), (2,'d'), (5, 'f')]

Thanks!

Upvotes: 1

Views: 1414

Answers (3)

Felix Kling
Felix Kling

Reputation: 817130

A simple way would be creating a dictionary, since it will only keep the last element with the same key:

In [1]: l = [(1,'a'), (1,'b'), (1,'c'), (2, 'd'), (5, 'e'), (5, 'f')]

In [2]: dict(l).items()
Out[2]: [(1, 'c'), (2, 'd'), (5, 'f')]

Update: As @Tadeck mentions in his comment, since the order of dictionary items is not guaranteed, you probably want to use an ordered dictionary:

from collections import OrderedDict
newl = OrderedDict(l).items()

If you actually want to keep the first tuple with the same key (and not the last, your question is ambiguous), then you could reverse the list first, add it do the dictionary and reverse the output of .items() again.
Though in that case there are probably better ways to accomplish this.

Upvotes: 4

Not_a_Golfer
Not_a_Golfer

Reputation: 49275

a nifty trick for one liner fetishists that keeps the order in place (I admit it's not very readable but you know...)

>>> s = [(1,'a'), (1,'b'), (1,'c'), (2, 'd'), (5, 'e'), (5, 'f')]
>>> seen = set()
>>> [seen.add(x[0]) or x for x in s if x[0] not in seen]
[(1, 'a'), (2, 'd'), (5, 'e')]

Upvotes: 2

MattH
MattH

Reputation: 38265

Using unique_everseen from itertools docs

from itertools import ifilterfalse
def unique_everseen(iterable, key=None):
    "List unique elements, preserving order. Remember all elements ever seen."
    # unique_everseen('AAAABBBCCDAABBB') --> A B C D
    # unique_everseen('ABBCcAD', str.lower) --> A B C D
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in ifilterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element

a = [(1,'a'), (1,'b'), (1,'c'), (2, 'd'), (5, 'e'), (5, 'f')]

print list(unique_everseen(a,key=lambda x: x[0]))

Yielding

[(1, 'a'), (2, 'd'), (5, 'e')]

Upvotes: 2

Related Questions