簡體   English   中英

命名元組列表; 如何計算單個元素的總和

[英]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)

但是想用只需要一行代碼的更通用的東西來替換總和:)

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)

您可以 zip 列表並使用“+”減少,這與您要求的數字相加很接近。 “+”連接字符串這可以工作:

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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM