Допустим, у меня есть 2D-список:

mylist = [[3,4,5,'x'],
          [6,1,4,'x'],
          [4,7,9,'y'],
          [0,4,3,'y'],
          [5,1,7,'z']]

Как бы я суммировал второй столбец, где четвертые элементы одинаковы (буквы)? В настоящее время я выделил четвертые элементы в список, избегая дублирования, с помощью:

newlist = list(set([r[3] for r in mylist]))

Который возвращает список ['z', 'y', 'x']

Я хочу получить его в формате вроде [['x', a], ['y', b]..] или в словаре, например {'x':a,...}

Где a - сумма второго столбца, где mylist[3]='x', который будет равен 4 + 1, а b такой же, но с y, и будет равен 7 + 4. Так что этот пример будет выводить [['x', 5], ['y', 11], ['z', 1]]

Каков был бы лучший способ сделать это? Или numpy / pandas справятся с этим лучше?

1
rharper 1 Май 2019 в 22:27

5 ответов

Лучший ответ

Это должно быть сделано, я использую zip

mylist = [[3,4,5,'x'],
          [6,1,4,'x'],
          [4,7,9,'y'],
          [0,4,3,'y'],
          [5,1,7,'z']]

#Zip all elements in the list
res = list(zip(*mylist))

#Zip the second column and character array
arr = list(zip(res[1], res[3]))
#[(4, 'x'), (1, 'x'), (7, 'y'), (4, 'y'), (1, 'z')]
dct = {}

#Calculate the sum
for num, key in arr:
    dct.setdefault(key,0)
    dct[key]+=num

print(dct)
#{'x': 5, 'y': 11, 'z': 1}

#Convert dict to list
li = []
for k, v in dct.items():
    li.append([k,v])

print(li)

На выходе будет

[['x', 5], ['y', 11], ['z', 1]]
4
Devesh Kumar Singh 1 Май 2019 в 19:40

Еще одним способом может быть использование defaultdict.

from collections import defaultdict

mylist = [
  [3,4,5,'x'],
  [6,1,4,'x'],
  [4,7,9,'y'],
  [0,4,3,'y'],
  [5,1,7,'z']
]

d = defaultdict(int)

for l in mylist:
  d[l[3]] += l[1]

# d: defaultdict(<class 'int'>, {'x': 5, 'y': 11, 'z': 1})
# dict(d) to convert to regular dict
0
tfw 1 Май 2019 в 19:44

Я предпочитаю панд для этой цели:

import pandas as pd
mylist = [[3,4,5,'x'],
          [6,1,4,'x'],
          [4,7,9,'y'],
          [0,4,3,'y'],
          [5,1,7,'z']]
df = pd.DataFrame(mylist)

Это дает:

print(df)
   0  1  2  3
0  3  4  5  x
1  6  1  4  x
2  4  7  9  y
3  0  4  3  y
4  5  1  7  z

Работа с группой панд:

print(df.groupby(3).sum())
   0   1   2
3           
x  9   5   9
y  4  11  12
z  5   1   7

print(df.groupby(3).sum()[1].to_dict())
{'x': 5, 'y': 11, 'z': 1}

Это оно

1
THandzsuj 1 Май 2019 в 19:54

Это может быть сделано путем зацикливания на каждом элементе в вашем списке, проверки 4-го места для x или y и добавления некоторого промежуточного итога:

mylist = [[3,4,5,'x'],
          [6,1,4,'x'],
          [4,7,9,'y'],
          [0,4,3,'y'],
          [5,1,7,'z']]

x_total = 0
y_total = 0
for i in mylist:
    if i[3] == "y":
        y_total += i[1]
    if i[3] == 'x':
        x_total += i[1]


print("x: ",x_total)
print("y: ",y_total)
1
Hoog 1 Май 2019 в 19:36

Вы можете использовать счетчик (из коллекции):

from collections import Counter
result = Counter()
for r in mylist: 
    result[r[3]] += r[1]

Вы также можете сделать это в одной строке:

result = Counter( r[3] for r in mylist for _ in range(r[1]) )

Или без использования счетчика:

result = dict()
for _,value,_,key in map(tuple,mylist):     # for r in mylist
    result[key] = result.get(key,0) + value #    result[r[3]]=result.get(r[3],0)+r[1]

Или

result = { r[3]:sum(v[1] for v in mylist if v[3]==r[3]) for r in mylist }

обратите внимание, что циклы for будут работать быстрее, чем однострочные

2
Alain T. 1 Май 2019 в 20:54