How can I get multiple lists as separate results from a list comprehension?

Question:

Suppose I have this code:

def f(x):
    return 2*x,x*x

x = range(3)
xlist, ylist = [f(value) for value in x]

How can I neatly get a result like this?

xlist = [0, 2, 4]
ylist = [0, 1, 4]
Asked By: Christophe

||

Answers:

Use

zip(*your_list_of_bituples)

Example

demo_list = [(1, 2), (2, 3), (4, 5)]
zip(*demo_list)

Will give

[(1, 2, 4), (2, 3, 5)]
Answered By: Elmex80s

Note that return 2*x,x is short for return (2*x,x), i.e. a tuple. Your list comprehension thus generates a list of tuples, not a tuple of lists. The nice thing of zip however is that you can easily use it in reverse with the asterisk:

xlist,ylist = zip(*[f(value) for value in x])
#                 ^ with asterisk

Note that xlist and ylist will be tuples (since zip will be unpacked). If you want them to be lists, you can for instance use:

xlist,ylist = map(list, zip(*[f(value) for value in x]))

which results in:

>>> xlist
[0, 2, 4]
>>> ylist
[0, 1, 4]

Another way to do this is with separate list comprehensions:

xlist = [f(value)[0] for value in x]
ylist = [f(value)[1] for value in x]

Of course, this repeats the work of f, which is inelegant and can be inefficient.

Answered By: Willem Van Onsem

Use the build-in function zip(),

def f(x):
  return 2*x, x*x

x = range(1, 4)
xlist, ylist = zip(*[f(value) for value in x])

print(xlist, ylist)
# ((2, 4, 6), (1, 4, 9))
Answered By: SparkAndShine

Let’s make this work. The function is fine:

def f(x):
  return 2*x, x*x

But you want to define the range as follows, notice the starting and ending values:

x = range(1, 4)

Also, you have to call the function with the value, not with the list as parameter. And the final trick to unzip the result into two lists, is to simply zip(*lst) the result of the list comprehension:

xlist, ylist = zip(*[f(value) for value in x])

Now the result is as expected:

xlist 
=> [2, 4, 6]
ylist 
=> [1, 4, 9]
Answered By: Óscar López

I know it’s late but the following gets what you want.

def f(value):
    xlist = []
    ylist = []
    for x, y in [(2*x, x*x) for x in range(value)]:
        xlist.append(x)
        ylist.append(y)
    return xlist, ylist

x = int(input("enter a value: "))
xval, yval = f(x)

print(f"xlist = {xval}nylist = {yval}")
Answered By: K. Solowoniuk
def f(x):
    yield [2*x, x*x]
        
xlist, ylist = zip(*[next(f(x)) for x in range(3)])

print(list(xlist))
print(list(ylist))

using yield…

[0, 2, 4]
[0, 1, 4]

[Program finished]
Answered By: Subham