簡體   English   中英

如何在某些子列表的字段中匯總多個列表列表?

[英]How do I sum multiple lists-of-lists on certain sub-list's fields?

我有3個列表清單。

子列表'字段1是名稱,字段2是數字,字段3是數字。 此格式始終相同,不會更改。 3個列表中總是有相同的名稱; 但是, 訂單可能不一樣

a = [['jane', '1', '120'], ['bob', '3', '35'], ['joe', '5', '70']]
b = [['bob', '1', '12'], ['jane', '2', '240'], ['joe', '1', '100']]
c = [['joe', '2', '30'], ['jane', '5', '45'], ['bob', '0', '0']]

我想要一個結果(任何對象類型)與列表的子列表的字段2和3的總和。

result = [['jane', '8', '405'], ['bob', '4', '47'], ['joe', '8', '200']]

在偽Python3代碼中,我猜它看起來像這樣,但我無法弄清楚在Python3中執行它的正確方法。 更別說以Pythonic方式做了:

def sum_f2_f3(list_a, list_b)
    where element[0] in list_a.sub_list == element[0] in list_b.sub_list:
        x = element[0]
        result[x:1] = list_a.sub_list[0:1] + list_b.sub_list[0:1]
        result[x:2] = list_a.sub_list[0:2] + list_b.sub_list[0:2]
    return result

result = sum_f2_f3(sum_f2_f3(a,b), c)

有任何想法嗎? 什么內置的Python工具可以幫助我解決這個問題?

這似乎使用更多pythonic列表推導給你想要的東西。

>>> [[e[0][0], sum(int(r[1]) for r in e), sum(int(r[2]) for r in e)] 
        for e in zip(a, b, c)]
[['jane', 8, 405], ['bob', 4, 47], ['joe', 8, 200]]

如果您希望它與無序名稱一起使用,您可以執行類似的操作

>>> from itertools import groupby
>>> [[name] + 
        reduce(
            lambda a, b: [int(c) + int(d) for (c,d) in zip(a, b)], 
            [r[1:] for r in records]) 
        for name, records 
        in groupby(
            sorted(r for l in [a, b, c] for r in l), 
            lambda r: r[0])
    ]

[['bob', 4, 47], ['jane', 8, 405], ['joe', 8, 200]]  

不要評判我。 我真的不是那樣寫代碼的。

為了說明為什么使用正確的數據結構會讓事情變得更容易......

假設abc實際上是dict s,你的數字實際上是int而不是str 畢竟, dict的全部意義在於按名稱查找事物,而int的整個要點是能夠進行算術運算。 所以:

a = {'jane': [1, 120], 'bob': [3, 35], 'joe': [5, 70]}
b = {'bob': [1, 12], 'jane': [2, 240], 'joe': [1, 100]}
c = {'joe': [2, 30], 'jane': [5, 45], 'bob': [0, 0]}

現在,你所要做的就是:

result = {}
for d in a, b, c:
    for k, v in d.items():
        if not k in result:
            result[k] = [0, 0]
        result[k][0] += v[0]
        result[k][1] += v[1]

結果是:

{'bob': [4, 47], 'jane': [8, 405], 'joe': [8, 200]}

還有一些改進的余地 - 你可以使用defaultdict來消除結果中的if not k in result: bit-but即使只是新手級別的東西,這也非常緊湊和簡單。


但是,如果你把這些列表作為輸入怎么辦 - 你最終會喜歡有好的詞匯,但是你不能從那里開始呢?

您可以編寫一個函數來轉換它們,如下所示:

def convert(list_of_lists):
    result = {}
    for element in list_of_lists:
        key = element[0]
        values = []
        for value in element[1:]:
            values.append(int(value))
        result[key] = values
    return result

如果您values = []… for value in … values.append(…)模式中發現了熟悉的values = []… for value in … values.append(…) ,則可以將其轉換[int(value) for value in element[1:]]的簡單列表解析[int(value) for value in element[1:]] 然后整個事情就是相同模式的dict,所以你可以把它全部減少到:

return {element[0]: [int(value) for value in element[1:]] for element in list_of_lists}

同時,如果你需要轉換回原始形式,那就是:

def unconvert(dict_of_lists):
    result = []
    for key, values in dict_of_lists.items():
        element = [key] + [str(value) for value in values]
        result.append(element)
    return result

使用dict ,這也適用於無序項目:

>>> from itertools import chain
>>> a = [['jane', '1', '120'], ['bob', '3', '35'], ['joe', '5', '70']]
>>> b = [['bob', '1', '12'], ['jane', '2', '240'], ['joe', '1', '100']]
>>> c = [['joe', '2', '30'], ['jane', '5', '45'], ['bob', '0', '0']]

for k in chain(a,b,c):
    if k[0] not in dic:
        dic[k[0]] = [ int(x) for x in k[1:]]
    else:
        dic[k[0]] = [x + int(y) for x,y in zip(dic[k[0]], k[1:])]

>>> [ [k]+[str(x) for x in v]  for k,v in dic.items()]
[['joe', '8', '200'], ['jane', '8', '405'], ['bob', '4', '47']]

Recursive的答案是最緊湊的合理方式,Ashwini Chaudhary是最靈活,最概念最好的......但如果你想知道如何使你的代碼幾乎完成:

你缺少的關鍵是“如何在鎖定步驟中迭代兩個列表?” 這正是zip的用途。 只需將兩個列表壓縮在一起,就可以得到:

[(['jane', '1', '120'], ['jane', '2', '240']),
 (['bob', '3', '35'], ['bob', '1', '12']),
 (['joe', '5', '70'], ['joe', '1', '100'])]

(除了它是迭代器,不是列表。)


你的其余代碼幾乎可以工作,除了你對名字有點困惑。 這是一個固定版本。

def sum_f2_f3(list_a, list_b):
    result = []
    for element_a, element_b in zip(list_a, list_b):
        result_element = [element_a[0],
                          element_a[1] + element_b[1],
                          element_a[2] + element_b[2]]
        result.append(result_element)
    return result

result = sum_f2_f3(sum_f2_f3(a,b), c)

除了你總結了一堆字符串。 這是完全合法的,但它得到的是這個:

[['jane', '125', '12024045'],
 ['bob', '310', '35120'],
 ['joe', '512', '7010030']]

您可能希望在某些時候將這些值轉換為int 如果沒有,如果你想轉換為int ,sum,並轉換回str ,這是非常簡單的:

def sum_f2_f3(list_a, list_b):
    result = []
    for element_a, element_b in zip(list_a, list_b):
        result_element = [element_a[0],
                          str(int(element_a[1]) + int(element_b[1])),
                          str(int(element_a[2]) + int(element_b[2]))]
        result.append(result_element)
    return result

一旦你有了這個,你可以通過多種方式來改進它。

例如,一旦你意識到你已經達到理解所針對的確切模式,你總是可以將results = []for循環和result.append(…)替換為列表理解:

def sum_f2_f3(list_a, list_b):
    return [[element_a[0],
             element_a[1] + element_b[1],
             element_a[2] + element_b[2]]
            for elementa, element_b in zip(list_a, list_b)]

或者,你可以概括它在所有三個列表一起工作,甚至任何數量lists-的zip已經這樣做,你只需更換+sum

def sum_f_lists(*lists):
    results = []
    for elements in zip(*lists):
        result_element = [elements[0][0],
                          sum(element[1] for element in elements),

sum(元素中元素的元素[2])] result.append(result_element)返回結果

或者你可以讓它適用於0或更多的數字而不是正好兩個,或者不依賴於排序等。當你走得足夠遠時,一步一步,你會得到類似於其他兩個答案之一的東西。

列表理解將再一次成功:

l = [a, b, c]
result =[ [e[0], sum( [int(ls[id][1]) for ls in l] ),
sum( [int(ls[id][2]) for ls in l] ) ] for id, e in enumerate(l[0])]

但是不要忘記Python的Zen所說的內容: Readability counts 如果他們需要太多的時間來理解,你應該避免單行。

既然你聲明any result type被接受,這里有一個表單返回一個dict,我認為這是一種適合這種工作的返回類型:

a = [['jane', '1', '120'], ['bob', '3', '35'], ['joe', '5', '70']]
b = [['jane', '2', '240'], ['bob', '1', '12'], ['joe', '1', '100']]
c = [['jane', '5', '45'], ['bob', '0', '0'], ['joe', '2', '30']]

def summation(*args):
    d = {}
    for name, v1, v2 in [item for sublist in args for item in sublist]:
        v1, v2 = int(v1), int(v2)
        try:
            d[name] = (d[name][0]+v1, d[name][1]+v2)
        except KeyError:
            d[name] = (v1, v2)

    return d

print summation(a,b,c)

退貨

{'jane': (8, 405), 'bob': (4, 47), 'joe': (8, 200)}

肯定有更緊湊,也許是高性能的選擇,但這種方法的優點(我相信!)是它看起來確實可讀。

暫無
暫無

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

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