Reputation: 159
I have 3 lists:
a = [1,2,3]
b = [4,5,6]
c = ['SUM','AVG','MAX']
I need to achieve:
d = [5,3.5,6]
Note that a and b are just an example. In reality I have a few hundred arrays with about one hundred elements. So I would prefer an interesting "Pythonian way" to achieve the d array, rather than looping around.
Something like similar to map
, for example:
d= [calculate(c, x) for x in [a,b]]
Is this possible?
Upvotes: 2
Views: 116
Reputation: 180481
If you have less functions than elements in the lists you can cycle the functions:
a = [1, 2, 3]
b = [4, 5, 6]
c = ['SUM', 'AVG', 'MAX']
mapped = {'SUM': sum, 'AVG': lambda x: sum(x, 0.0) / len(x), 'MAX': max}
from itertools import cycle
def calc(funcs, *args):
_fncs = list(map(mapped.get, funcs))
return [f(it) for f, it in zip(cycle(_fncs), zip(*args))]
If c is shorter than a and b then the functions will be cycled, if the lists are different lengths you can use itertools.izip_longest
but you will have to decide what an appropriate fillvalue is.
If you are using python 3 there is also a builtin for the average:
mapped = {'SUM': sum, 'AVG': mean, 'MAX': max}
from itertools import cycle
from statistics import mean
def calc(funcs, *args):
_fncs = list(map(mapped.get, funcs))
return [f(it) for f, it in zip(cycle(_fncs), zip(*args))]
If they are always going to be even lengths you don't need the cycle:
def calc(funcs, *args):
_fncs = map(mapped.get, funcs)
return [f(it) for f, it in zip(_fncs, zip(*args))]
Upvotes: 1
Reputation: 24062
Here's one way to do this:
op_dict = {
'SUM' : lambda x, y: x + y,
'AVG' : lambda x, y: (x + y) / 2.0,
'MAX' : max
}
a = [1,2,3]
b = [4,5,6]
c = ['SUM','AVG','MAX']
d = [op_dict[z](x, y) for x, y, z in zip(a, b, c)]
Here's a more powerful version that can handle any number of lists, but they must still all be the same length:
op_dict = {
'SUM' : lambda *x: sum(x),
'AVG' : lambda *x: sum(x) / float(len(x)),
'MAX' : max
}
ops = ['SUM', 'AVG', 'MAX']
a = [1, 2, 3]
b = [4, 5, 6]
c = [7, 8, 9]
d = [10, 11, 12]
args = [ops, a, b, c, d]
r = [op_dict[x[0]](*x[1:]) for x in zip(*args)]
Upvotes: 4
Reputation: 153
How about:
def sum(a, b):
return a + b
def avg(a, b):
return a + b / 2.0
def calculate(a, b, c):
mapping = {'SUM': sum,
'AVG': avg,
'MAX': max}
return mapping[c](a,b)
d = [calculate(a1,b1,c1) for a1,b1,c1 in zip(a, b, c)]
So, working from the bottom up:
edit: I love how we've all given essentially the same answer, within a small period of time. Kinda reassures you that this is the way to do it.
Obviously syntatic sugar like lambdas help keep the code looking simpler.
Upvotes: 0