0

I need to convert a Dictionary to a List where the key is repeated the number of times of the value.

dict = {'foo':3, 'bar':1}

expect result:

['foo', 'foo', 'foo', 'bar']
John Doe
  • 9,843
  • 13
  • 42
  • 73
  • Also: [Iterate through Python dictionary and special append to new list?](https://stackoverflow.com/q/54802168/7851470) – Georgy Aug 06 '20 at 14:10

6 Answers6

6

Using collections.Counter:

>>> [*Counter(dict).elements()]
['foo', 'foo', 'foo', 'bar']

A little benchmark comparing this with a supposedly faster solution (and a third solution, doing what Counter does, but directly to the dict). Numbers are times, so lower=faster:

0.31 Counter
0.70 listcomp
0.27 itertools

0.32 Counter
0.72 listcomp
0.28 itertools

0.32 Counter
0.72 listcomp
0.29 itertools

Benchmark code:

import timeit
from collections import Counter
from itertools import chain, starmap, repeat

data = {i: i % 10 + 1 for i in range(1000)}

solutions = {
    'Counter':   lambda: [*Counter(data).elements()],
    'listcomp':  lambda: [v for v, c in data.items() for _ in range(c)],
    'itertools': lambda: list(chain.from_iterable(starmap(repeat, data.items())))
    }

for _ in range(3):
    for name, solution in solutions.items():
        t = min(timeit.repeat(solution, number=1000))
        print('%.2f' % t, name)
    print()
superb rain
  • 5,300
  • 2
  • 11
  • 25
  • 1
    @superbrain Holy sh*t, that doesn't make sense to me! Calling 3 methods, unpacking, casting to list is faster than a plain list comprehension? How come?! Time complexity should be somewhat similar, as a nested loop flattens to the same number of iterations as the number of elements in the result. – VisioN Aug 06 '20 at 10:03
  • @VisioN I guess it's because of C speed vs Python speed. The list comprehension runs some Python for every element. – superb rain Aug 06 '20 at 10:05
  • @superbrain But list comprehension is also implemented in C. Maybe the slowness comes from the range object? Anyways, I have to remove my initial comment, as it seems to be totally wrong. Good catch! – VisioN Aug 06 '20 at 10:08
  • @VisioN Well, the list comprehension "itself" is implemented in C. But it's evaluating your Python expressions all the time. – superb rain Aug 06 '20 at 10:11
  • 1
    `[item for k,v in data.items() for item in [k]*v]` doesn't call `range()` and it will be about 25% faster than the former listcomp. Still slower than the other two solutions. – alec_djinn Aug 06 '20 at 10:14
2

Use a list comprehension to create a sub lists of required length and then flatten it:

list(chain.from_iterable([[k] * v for k, v in dict.items()]))

Example:

from itertools import chain

dict = {'foo':3, 'bar':1}

print(list(chain.from_iterable([[k] * v for k, v in dict.items()])))
# ['foo', 'foo', 'foo', 'bar']
Austin
  • 25,759
  • 4
  • 25
  • 48
2

you can use simple list comprehension to complete the job.

mylist = [key for key, value in mydict.items() for _ in range(value)]

Output:

['foo', 'foo', 'foo', 'bar']
Vishal Singh
  • 6,014
  • 2
  • 17
  • 33
1

Try this:

dict = {'foo':3, 'bar':1}
my_list = []
for key, value in dict.items():
    for _ in range(value):
        my_list.append(key)

Output:

['foo', 'foo', 'foo', 'bar']
Almog
  • 452
  • 1
  • 7
  • 13
1
if __name__ == '__main__':
    result = []
    dict = {'foo': 3, 'bar': 1}
    for key in dict.keys():
        key_value = dict[key]
        for i in range(key_value):
            result.append(key)
    print(result)

or you could do:

if __name__ == '__main__':
    result = []
    dict = {'foo': 3, 'bar': 1}
    result = [k for k, v in dict.items() for _ in range(v)]
    print(result)

Both Outputs are:

['foo', 'foo', 'foo', 'bar']
Ahmet
  • 7,527
  • 3
  • 23
  • 47
1

Here is a simple way using plain list comprehension coupled with list multiplication.

d = {'foo':3, 'bar':1}
l = [item for k,v in d.items() for item in [k]*v]
print(l)

['foo', 'foo', 'foo', 'bar']
alec_djinn
  • 10,104
  • 8
  • 46
  • 71