命名元组列表;如何计算单个元素的总和
list of namedtuples; how to calculate the sum of individual elements
假设我命名了元组:
Trade = namedtuple('Trade', ['Ticker', 'Date', 'QTY', 'Sell', 'Buy', 'Profit'])
是否有任何 'pythonic' 方法可以对列表中的每个 'summable' 或 'selected'(QTY、Sell、Buy、Profit)元素进行单行求和?
listofstuff = []
Trade1 = Trade(Ticker='foo', Date='{2020:12:24}', QTY=100, Sell=500.0, Buy=100.0, Profit=400.0)
Trade2 = Trade(Ticker='foo', Date='{2020:12:24}', QTY=50, Sell=50.0, Buy=500.0, Profit=-450.0)
listofstuff.append(Trade1)
listofstuff.append(Trade2)
预期结果:
Trade(Ticker='do not care', Date='do not care', QTY=150.0, Sell = 550.0, Buy = 600.0,0 Profit=-50.0)
我知道我可以执行以下操作,需要 4 行代码:
tot_QTY = sum(i.QTY for i in listofstuff)
tot_Sell = sum(i.Sell for i in listofstuff)
tot_Buy = sum(i.Buy for i in listofstuff)
tot_Profit = sum(i.Profit for i in listofstuff)
x = Trade(Ticker=listofstuff[0].Ticker, Date=listofstuff[0].Date, QTY=tot_QTY,
Sell=tot_Sell, Buy=tot_Buy, Profit=tot_Profit)
但是我想用更通用的东西替换总和,只需要 1 行代码:)
total = sum(listofstuff) # most likely cannot calc sums of 'ticker' nor ' date' but I do not care since I can use original [0] items for those..
然后创建'x',就像使用列表中各个元素的总和一样
x = Trade(Ticker=listofstuff[0].Ticker, Date=listofstuff[0].Date, QTY=total.QTY,
Sell=total.Sell, Buy=total.Buy, Profit=total.Profit)
我们可以这样看:sum
只是一个以加法运算为函数的输入列表reduce
。所以我们可以定义我们自己的操作:
def add_trades(x, y):
return Trade(x.Ticker, x.Date, x.QTY + y.QTY, x.Sell + y.Sell, x.Buy + y.Buy, x.Profit + y.Profit)
并将其与 reduce
一起使用:
from functools import reduce
x = reduce(add_trades, listofstuff)
print(x)
# Gives: Trade(Ticker='foo', Date='{2020:12:24}', QTY=150, Sell=550.0, Buy=600.0, Profit=-50.0)
为了使 add_trades
函数更通用,您可以迭代元组的 _fields
并 try
添加它们:
def add_trades(x, y):
new_fields = []
for field in x._fields:
try:
new_fields.append(getattr(x, field) + getattr(y, field))
except TypeError:
new_fields.append(getattr(x, field))
return Trade._make(new_fields)
您可以压缩列表并使用“+”进行缩减,这与您要求的数字相加很接近。 “+”连接字符串这可以工作:
from functools import reduce
import operator
sums = [reduce(operator.add,i) for i in zip(*listofstuff)]
sums[:2] = listofstuff[0].Ticker,listofstuff[0].Date
Trade(*sums)
Trade(Ticker='foo', Date='{2020:12:24}', QTY=150, Sell=550.0, Buy=600.0, Profit=-50.0)
如果您不关心非数字值的值是多少,您可以使用 zip 来形成一个包含总计的新元组:
R = Trade(*((max,sum)[isinstance(v[0],(int,float))](v)
for v in zip(*listofstuff)))
print(R)
Trade(Ticker='foo', Date='{2020:12:24}', QTY=150, Sell=550.0,
Buy=600.0, Profit=-50.0)
或者,您可以在非总计字段中放置一个 None 值:
R = Trade(*( sum(v) if isinstance(v[0],(int,float)) else None
for v in zip(*listofstuff)))
print(R)
Trade(Ticker=None, Date=None, QTY=150, Sell=550.0, Buy=600.0, Profit=-50.0)
如果聚合类型因每个字段而异(例如某些字段为min,其他字段为sum等),您可以准备一个聚合函数字典并在理解中使用它:
aggregate = {'QTY':sum, 'Sell':min, 'Buy':max, 'Profit':lambda v:sum(v)/len(v)}
R = Trade(*(aggregate.get(f,lambda _:None)(v)
for f,v in zip(Trade._fields,zip(*listofstuff))))
print(R)
Trade(Ticker=None, Date=None, QTY=150, Sell=50.0, Buy=500.0, Profit=-25.0)
假设我命名了元组:
Trade = namedtuple('Trade', ['Ticker', 'Date', 'QTY', 'Sell', 'Buy', 'Profit'])
是否有任何 'pythonic' 方法可以对列表中的每个 'summable' 或 'selected'(QTY、Sell、Buy、Profit)元素进行单行求和?
listofstuff = []
Trade1 = Trade(Ticker='foo', Date='{2020:12:24}', QTY=100, Sell=500.0, Buy=100.0, Profit=400.0)
Trade2 = Trade(Ticker='foo', Date='{2020:12:24}', QTY=50, Sell=50.0, Buy=500.0, Profit=-450.0)
listofstuff.append(Trade1)
listofstuff.append(Trade2)
预期结果:
Trade(Ticker='do not care', Date='do not care', QTY=150.0, Sell = 550.0, Buy = 600.0,0 Profit=-50.0)
我知道我可以执行以下操作,需要 4 行代码:
tot_QTY = sum(i.QTY for i in listofstuff)
tot_Sell = sum(i.Sell for i in listofstuff)
tot_Buy = sum(i.Buy for i in listofstuff)
tot_Profit = sum(i.Profit for i in listofstuff)
x = Trade(Ticker=listofstuff[0].Ticker, Date=listofstuff[0].Date, QTY=tot_QTY,
Sell=tot_Sell, Buy=tot_Buy, Profit=tot_Profit)
但是我想用更通用的东西替换总和,只需要 1 行代码:)
total = sum(listofstuff) # most likely cannot calc sums of 'ticker' nor ' date' but I do not care since I can use original [0] items for those..
然后创建'x',就像使用列表中各个元素的总和一样
x = Trade(Ticker=listofstuff[0].Ticker, Date=listofstuff[0].Date, QTY=total.QTY,
Sell=total.Sell, Buy=total.Buy, Profit=total.Profit)
我们可以这样看:sum
只是一个以加法运算为函数的输入列表reduce
。所以我们可以定义我们自己的操作:
def add_trades(x, y):
return Trade(x.Ticker, x.Date, x.QTY + y.QTY, x.Sell + y.Sell, x.Buy + y.Buy, x.Profit + y.Profit)
并将其与 reduce
一起使用:
from functools import reduce
x = reduce(add_trades, listofstuff)
print(x)
# Gives: Trade(Ticker='foo', Date='{2020:12:24}', QTY=150, Sell=550.0, Buy=600.0, Profit=-50.0)
为了使 add_trades
函数更通用,您可以迭代元组的 _fields
并 try
添加它们:
def add_trades(x, y):
new_fields = []
for field in x._fields:
try:
new_fields.append(getattr(x, field) + getattr(y, field))
except TypeError:
new_fields.append(getattr(x, field))
return Trade._make(new_fields)
您可以压缩列表并使用“+”进行缩减,这与您要求的数字相加很接近。 “+”连接字符串这可以工作:
from functools import reduce
import operator
sums = [reduce(operator.add,i) for i in zip(*listofstuff)]
sums[:2] = listofstuff[0].Ticker,listofstuff[0].Date
Trade(*sums)
Trade(Ticker='foo', Date='{2020:12:24}', QTY=150, Sell=550.0, Buy=600.0, Profit=-50.0)
如果您不关心非数字值的值是多少,您可以使用 zip 来形成一个包含总计的新元组:
R = Trade(*((max,sum)[isinstance(v[0],(int,float))](v)
for v in zip(*listofstuff)))
print(R)
Trade(Ticker='foo', Date='{2020:12:24}', QTY=150, Sell=550.0,
Buy=600.0, Profit=-50.0)
或者,您可以在非总计字段中放置一个 None 值:
R = Trade(*( sum(v) if isinstance(v[0],(int,float)) else None
for v in zip(*listofstuff)))
print(R)
Trade(Ticker=None, Date=None, QTY=150, Sell=550.0, Buy=600.0, Profit=-50.0)
如果聚合类型因每个字段而异(例如某些字段为min,其他字段为sum等),您可以准备一个聚合函数字典并在理解中使用它:
aggregate = {'QTY':sum, 'Sell':min, 'Buy':max, 'Profit':lambda v:sum(v)/len(v)}
R = Trade(*(aggregate.get(f,lambda _:None)(v)
for f,v in zip(Trade._fields,zip(*listofstuff))))
print(R)
Trade(Ticker=None, Date=None, QTY=150, Sell=50.0, Buy=500.0, Profit=-25.0)