2016-10-22 3 views
0

Мне нужно объединить два списка, а затем подсчитать все значения, соответствующие определенному значению.Объединение двух списков и печать всех значений, соответствующих определенному значению

В два списка:

inControl = ["False", "False", "True", "True","False", "True", "False", "True", "True", "False", "False", "False", "False", "False", "False", "True", "False", "True", "False", "False"] 

rts = [379, 396, 480, 443, 365, 280, 487, 446, 350, 367, 405, 391, 484, 359, 367, 305, 359, 479, 436, 333] 

мне нужно суммировать все rts, соответствующий всем False значений, а затем то же самое для True значений (они все в порядке).

Я в основном добрался до двух списков, используя функцию zip, но полностью потерял, что делать дальше ... любая помощь будет оценена.

Большое спасибо :)

+0

Посмотрите на 'itertools' и специально на' groupby'. См. Документы [здесь] (https://docs.python.org/2/library/itertools.html#itertools.groupby) –

+0

@TammoHeeren: для 'groupby':« Как правило, итерабельность должна быть уже отсортирована на той же ключевой функции ". Здесь нужно отсортировать кортежи. –

+0

@ Jean-FrançoisFabre Хороший комментарий. Вы абсолютно правы. Должен быть отсортирован на 'inControl' здесь. –

ответ

2

кажется странным, что булевы являются строками, но ...

Использование zip, затем sum на соответствующие элементы.

(повторно создать zip для другой части в Python 3, поскольку zip является итерацию)

inControl = ["False", "False", "True", "True","False", "True", "False", "True", "True", "False", "False", "False", "False", "False", "False", "True", "False", "True", "False", "False"] 

rts = [379, 396, 480, 443, 365, 280, 487, 446, 350, 367, 405, 391, 484, 359, 367, 305, 359, 479, 436, 333] 

z=zip(rts,inControl) 
sf=sum(x[0] for x in z if x[1]=='False') 
z=zip(rts,inControl) 
st=sum(x[0] for x in z if x[1]=='True') 
print(sf,st) 

результат:

5128 2783 

Может st может быть вычислена с меньшим количеством сравнения строк с sum : st=sum(rts)-sf (больше дополнений, без сравнения строк)

варианта: небольшая петля для истинного & ложного

s=dict() 

for c in ['False','True']: 
    z=zip(rts,inControl) 
    s[c]=sum(x[0] for x in z if x[1]==c) 
2

решения Жана-Франсуа будет работать нормально и довольно читаемый. Однако он делает два прохода над данными. Если список небольшой, это не имеет большого значения, но если он большой, вы можете примерно вдвое сократить время работы, выполнив один проход.

Один общий подход заключается в следующем:

totals = {} 
for flag, value in zip(inControl, rts): 
    totals[flag] = totals.setdefault(flag, 0) + value 

Этот код не предполагает, что inControl имеет только False и True. На самом деле он может иметь любое количество уникальных значений.

Простым способом является использование класса Counter из модуля collections. A Counter - это словарь, предназначенный для отслеживания отсчетов. Добавление двух счетчиков делает очевидную вещь: значения идентичных ключей суммируются. Мы можем создать экземпляр Counter для каждой пары элементов и добавить все счетчики. Обратите внимание, что создание Counter для каждого элемента, вероятно, слишком велико - вышеупомянутое решение более эффективно.Но для образовательных целей, это решение выглядит следующим образом:

from collections import Counter 
counters = (Counter({k: v}) for k, v in zip(inControl, rts)) 
sum(counters, Counter()) 
+0

Ваше первое решение очень эффективно. Как сделать немного больше, инициализируя 'totals = {'True': 0, 'False': 0}'. Таким образом, вам не нужно вызывать 'setdefault' внутри цикла. –

0

Вы можете производить кортежи, которые имеют один номер либо в False позиции или True позиции в списке понимания или генератора exrpession:

>>> [(e,0) if c=='False' else (0,e) for e, c in zip(rts, inControl)] 
[(379, 0), (396, 0), (0, 480), (0, 443), (365, 0), (0, 280), (487, 0), (0, 446), (0, 350), (367, 0), (405, 0), (391, 0), (484, 0), (359, 0), (367, 0), (0, 305), (359, 0), (0, 479), (436, 0), (333, 0)] 

You можно просуммировать ряд кортежей с reduce:

>>> reduce(lambda x, y: (x[0]+y[0], x[1]+y[1]), (((e,0) if c=='False' else (0,e) for e, c in zip(rts, inControl)))) 
(5128, 2783) 

Вы можете использовать False и True булевы для доступа к кортежу:

>>> t=reduce(lambda x, y: (x[0]+y[0], x[1]+y[1]), ((e if c=='False' else 0, e if c=='True' else 0) for e, c in zip(rts, inControl))) 
>>> t[False] 
5128 
>>> t[True] 
2783 

Или, вы можете использовать map, если это имеет смысл для вас:

>>> map(sum, zip(*((e,0) if c=='False' else (0,e) for e, c in zip(rts, inControl)))) 
[5128, 2783] 

Или, вы можете создать Dict с суммами:

>>> dict(zip([False, True], map(sum, zip(*[(e,0) if c=='False' else (0,e) for e, c in zip(rts, inControl)])))) 
{False: 5128, True: 2783} 

Если у вас есть панда, отличный способ сделать это с .groupby() и sum:

>>> import pandas as pd 
>>> df=pd.DataFrame({'rts':rts, 'inControl':inControl}) 
>>> df 
    inControl rts 
0  False 379 
1  False 396 
2  True 480 
3  True 443 
4  False 365 
5  True 280 
6  False 487 
7  True 446 
8  True 350 
9  False 367 
10  False 405 
11  False 391 
12  False 484 
13  False 359 
14  False 367 
15  True 305 
16  False 359 
17  True 479 
18  False 436 
19  False 333 
>>> df.groupby(inControl).sum() 
     rts 
False 5128 
True 2783 
+0

Могу ли я спросить, почему голос? – dawg

0

Дано:

inControl = ["False", "False", "True", "True","False", "True", "False", "True", "True", "False", "False", "False", "False", "False", "False", "True", "False", "True", "False", "False"] 
rts = [379, 396, 480, 443, 365, 280, 487, 446, 350, 367, 405, 391, 484, 359, 367, 305, 359, 479, 436, 333] 

Я предполагаю, что inControl список строк, а не список булевы. Для мое решение работать, я собираюсь преобразовать inControl в список логических значений:

inControl = [element == 'True' for element in inControl] # ==> [False, False, ...] 

Использование itertools.compress вычислить сумму всех True элементов:

import itertools 
true_sum = sum(itertools.compress(rts, inControl)) # 2783 

Теперь мы можем вычислить false_sum:

grand_sum = sum(rts)    # 7911 
false_sum = grand_sum - true_sum # 5128