7

Given a list I need to return a list of lists of unique items. I'm looking to see if there is a more Pythonic way than what I came up with:

def unique_lists(l):
    m = {}
    for x in l:
        m[x] = (m[x] if m.get(x) != None else []) + [x]
    return [x for x in m.values()]    

print(unique_lists([1,2,2,3,4,5,5,5,6,7,8,8,9]))

Output:

[[1], [2, 2], [3], [4], [5, 5, 5], [6], [7], [8, 8], [9]]
Yuriy Zubarev
  • 2,821
  • 18
  • 24

3 Answers3

9
>>> L=[1,2,2,3,4,5,5,5,6,7,8,8,9]
>>> from collections import Counter
>>> [[k]*v for k,v in Counter(L).items()]
[[1], [2, 2], [3], [4], [5, 5, 5], [6], [7], [8, 8], [9]]
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
  • 1
    I originally posted a solution that was one line shorter by simply using the list's built in count method, but gnibbler makes the excellent point that list.count() is O(n), making my algorithm O(n^2). +1 – Nolen Royalty Mar 30 '12 at 04:08
  • 3
    There's no reason that the creation of the `Counter` can't be folded into the list comprehension here: `[[k]*v for k, v in Counter(L).items()]`. – Karl Knechtel Mar 30 '12 at 04:13
  • 1
    My rule of thumb is to automatically elide temporaries that are only written once and read once, unless they represent significant complexity ("flat is better than nested"). – Karl Knechtel Mar 30 '12 at 05:49
2

Using default dict.

>>> from collections import defaultdict
>>> b = defaultdict(list)
>>> a = [1,2,2,3,4,5,5,5,6,7,8,8,9]
>>> for x in a:
...     b[x].append(x)
...
>>> b.values()
[[1], [2, 2], [3], [4], [5, 5, 5], [6], [7], [8, 8], [9]]
Amjith
  • 22,626
  • 14
  • 43
  • 38
0

I find the build in function set() useful very often:

lst=[1,2,2,3,4,5,5,5,6,7,8,8,9]

def all_eq_elms(lst, elm):
    while True:
        try:
            yield lst.pop(lst.index(elm))
        except:
            break

[[e for e in all_eq_elms(lst,elm)] for elm in set(lst)]

Out[43]: [[1], [2, 2], [3], [4], [5, 5, 5], [6], [7], [8, 8], [9]]
Bastiaan
  • 4,451
  • 4
  • 22
  • 33