Editor

Unique, in Order

#334 · Iterators and generators · Intermediate · 80 XP · about 15 min

Write a generator unique(iterable, key=None) that yields each item of iterable the first time it appears and skips every later item equal to it.

  • If key is a function, two items count as the same when their keys are equal; the item yielded is the first one with that key.
  • Items (or keys) may be unhashable, like lists or dicts. Those cannot go in a set, so compare them with == against the unhashable ones seen before. Hashable ones must still be checked with a set, because a stream can hold hundreds of thousands of them.

It must be lazy: it yields each new item as soon as it reads it, so it also works on endless iterables.

Examples

list(unique([3, 1, 3, 2, 1]))                              # returns [3, 1, 2]
list(unique(['Apple', 'apple', 'Banana'], key=str.lower))  # returns ['Apple', 'Banana']
list(unique([[1, 2], [3], [1, 2]]))                        # returns [[1, 2], [3]]

from itertools import count, islice
list(islice(unique(n % 4 for n in count()), 4))            # returns [0, 1, 2, 3]

Constraints

  • Up to 200,000 items, or endless
  • In the tests, a hashable item (or key) is never equal to an unhashable one

Fastest solvers

Leaderboard

First solves only, ranked by stars and then time.