4

This question here goes nearly where I want. However, my dictionary has a list inside a list for each key, such as:

test = {1092268: [[81, 90], [78, 90]], 
        524292: [[80, 80], [65, 78]], 
        892456: [[88, 81], [81, 88]]}

The suggestion that Works when there is just one list inside each key is:

xs, ys = zip(*test.values())

How can I unpack (still xs and ys), but from multiple lists?

For the example, the results I expect are:

xs = [81, 78, 80, 65, 88, 81]
ys = [90, 90, 80, 78, 81, 88]
cs95
  • 379,657
  • 97
  • 704
  • 746
B Furtado
  • 1,488
  • 3
  • 20
  • 34

2 Answers2

4

Not much changes, just flatten your values in advance.

itertools.chain

from itertools import chain
xs, ys = zip(*chain.from_iterable(test.values()))

Of course, this returns tuples. If you want lists instead, I recommend adding a map call—

xs, ys = map(list, zip(*chain.from_iterable(test.values())))

print(xs)
[81, 78, 80, 65, 88, 81]

print(ys)
[90, 90, 80, 78, 81, 88]

Comprehension-based

This is the alternative, squash nested loops into a single line (i.e., a nested list comprehension)—

xs, ys = map(list, zip(*[j for i in test.values() for j in i]))

print(xs)
[81, 78, 80, 65, 88, 81]

print(ys)
[90, 90, 80, 78, 81, 88]

However, I recommend itertools.chain because it has been shown to outperform nested list comprehensions, comprehensively (...hah).

cs95
  • 379,657
  • 97
  • 704
  • 746
  • 1
    I like this answer using `itertools.chain`. Upvoted. – Mihai Alexandru-Ionut May 16 '18 at 20:15
  • 1
    @MihaiAlexandru-Ionut Always happy to return good sportsmanship in kind. Your answer is quite nice in its own right. – cs95 May 16 '18 at 20:15
  • Just curious: there are any advantages of using `itertool.chain` over `reduce` or `list comprehension` ? – Mihai Alexandru-Ionut May 16 '18 at 20:17
  • 1
    @MihaiAlexandru-Ionut Yes. I believe reduce is a quadratic time method for joining lists, as is the list comprehension. The chain method is _very_ efficient, and from my tests consistently outperforms the other two. By the way, reduce is equivalent to `sum(list_of_lists, [])`. – cs95 May 16 '18 at 20:18
  • 1
    In this answer there are some tests: https://stackoverflow.com/a/953097/6583140 and it's seems that chain is fastest. – Mihai Alexandru-Ionut May 16 '18 at 20:22
  • However, `itertools` package contains functions for creating iterators for efficient looping. – Mihai Alexandru-Ionut May 16 '18 at 20:24
  • 1
    @MihaiAlexandru-Ionut It finds applications in the funniest of places, including pandas... ;-) – cs95 May 16 '18 at 20:25
3

Another approach is to use reduce method by passing a lambda expression as first argument.

from functools import reduce
xs, ys = zip(*reduce(lambda x, y : x + y, test.values()))

A faster way to do the reduce version could be using concat operator.

xs, ys = zip(*reduce(operator.concat, test.values()))
Mihai Alexandru-Ionut
  • 47,092
  • 13
  • 101
  • 128