-->

Pythonic way to append output of function to sever

2019-07-26 15:15发布

问题:

I have a question that I haven't quite found a good solution to. I'm looking for a better way to append function output to two or more lists, without using temp variables. Example below:

def f():
  return 5,6

a,b = [], []
for i in range(10):
  tmp_a, tmp_b = f()
  a.append(tmp_a)
  b.append(temp_b)

I've tried playing around with something like zip(*f()), but haven't quite found a solution that way. Any way to remove those temp vars would be super helpful though, thanks!

Edit for additional info: In this situation, the number of outputs from the function will always equal the number of lists that are being appended to. The main reason I'm looking to get rid of temps is for the case where there are maybe 8-10 function outputs, and having that many temp variables would get messy (though I don't really even like having two).

回答1:

def f():
    return 5,6

a,b = zip(*[f() for i in range(10)])
# this will create two tuples of elements 5 and 6 you can change 
# them to list by type casting it like list(a), list(b)


回答2:

First solution: we make a list of all results, then transpose it

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

# First make a list of all your results
l = [f(i) for i in range(5)]
# [(0, 0), (1, 2), (2, 4), (3, 6), (4, 8)]

# then transpose it using zip
a, b = zip(*l)

print(list(a))
print(list(b))
# [0, 1, 2, 3, 4]
# [0, 2, 4, 6, 8]

Or, all in one line:

a, b = zip(*[f(i) for i in range(5)])

A different solution, building the lists at each iteration, so that you can use them while they're being built:

def f(i):
    return 2*i, i**2, i**3

doubles = []
squares = []
cubes = []
results = [doubles, squares, cubes]

for i in range(1, 4):
    list(map(lambda res, val: res.append(val), results, f(i)))
    print(results)

# [[2], [1], [1]]
# [[2, 4], [1, 4], [1, 8]]
# [[2, 4, 6], [1, 4, 9], [1, 8, 27]]

print(cubes)
# [1, 8, 27]

Note about list(map(...)): in Python3, map returns a generator, so we must use it if we want the lambda to be executed.list does it.



回答3:

For your specific case, the zip answers are great.

Using itertools.cycle and itertools.chain is a different approach from the existing answers that might come in handy if you have a lot of pre-existing lists that you want to append to in a round-robin fashion. It also works when your function returns more values than you have lists.

>>> from itertools import cycle, chain
>>> a, b = [], [] # new, empty lists only for demo purposes
>>> for l, v in zip(cycle([a, b]), (chain(*(f() for i in range(10))))):
...     l.append(v)
... 
>>> a
[5, 5, 5, 5, 5, 5, 5, 5, 5, 5]
>>> b
[6, 6, 6, 6, 6, 6, 6, 6, 6, 6]


回答4:

I'd do

tmp = f()
a.append(tmp[0])
b.append(tmp[1])

Not sure how pythonic it is for you though.