Подтвердить что ты не робот

Поиск дубликатов в списке списков

Я использую Python 2.7 и пытаюсь удалить дубликаты списка списков и объединить значения дубликатов.

Сейчас у меня есть:

original_list = [['a', 1], ['b', 1], ['a', 1], ['b', 1], ['b', 2], ['c', 2], ['b', 3]]

Я хочу сопоставить первый элемент каждого вложенного списка, а затем добавить значения второго элемента. Я хочу закончить с этим (порядок окончательного списка не имеет значения):

ideal_output = [['a', 2], ['b', 7], ['c', 2]]

До сих пор у меня есть код, который найдет мне повторяющиеся значения, основанные на первом элементе каждого вложенного списка:

for item in original_list:
    matches = -1
    for x in original_list:
        if (item[0] == x[0]):
            matches += 1
    if matches >= 1: 
        if item[0] not in duplicates_list:
            duplicates_list.append(item[0])

Отсюда мне нужно найти все элементы duplicates_list, которые находятся в original_list, и добавить значения, но я не уверен, что лучший способ сделать это.

4b9b3361

Ответ 1

Много хороших ответов, но все они используют скорее больше кода, чем я для этого, поэтому здесь я беру, для чего это стоит:

totals = {}
for k,v in original_list:
  totals[k] = totals.get(k,0) + v

# totals = {'a': 2, 'c': 2, 'b': 7}

Как только у вас есть такой диктофон, из любого из этих ответов вы можете использовать items для получения списка кортежей:

totals.items()
# => [('a', 2), ('c', 2), ('b', 7)]

И сопоставьте list по кортежам, чтобы получить список списков:

map(list, totals.items())
# => [['a', 2], ['c', 2], ['b', 7]]

И сортируйте, если вы хотите их в порядке:

sorted(map(list, totals.items()))
# => [['a', 2], ['b', 7], ['c', 2]]

Ответ 2

>>> from collections import Counter
>>> lst = [['a', 1], ['b', 1], ['a', 1], ['b', 1], ['b', 2], ['c', 2], ['b', 3]]
>>> c = Counter(x for x, c in lst for _ in xrange(c))

Counter({'b': 7, 'a': 2, 'c': 2})

>>> map(list, c.iteritems())
[['a', 2], ['c', 2], ['b', 7]]

Или, альтернативно, не повторяя каждый элемент (a, b) b раз (@hcwhsa):

>>> from collections import Counter
>>> lst = [['a', 1], ['b', 1], ['a', 1], ['b', 1], ['b', 2], ['c', 2], ['b', 3]]
>>> c = sum((Counter(**{k:v}) for k, v in lst), Counter())

Counter({'b': 7, 'a': 2, 'c': 2})

>>> map(list, c.iteritems())
[['a', 2], ['c', 2], ['b', 7]]

Ответ 3

Решение

Используйте collections.Counter:

from collections import Counter
original_list = [['a', 1], ['b', 1], ['a', 1], ['b', 1], ['b', 2], ['c', 2], ['b', 3]]
result = Counter()
for k, v in original_list:
     result.update({k:v})

map(list, result.items())
# [['a', 2], ['c', 2], ['b', 7]]

НАХОДКИ

Итак, много ответов, просмотров и опросов. Я даже заработал свой первый Nice answer из ничего (за последние 2 дня я дал много ответов, заслуживающих больше исследований и усилий). В связи с этим я решил сделать хотя бы некоторые исследования и испытания решений с помощью простого script, написанного с нуля. Не включайте код непосредственно в ответ ради размера.

Каждая функция называется для нее автором, которую легко найти в вопросе. Решение thefourtheye теперь равно одному из Mark Reed и оценивается в оригинальной форме, а fourtheye2 - для решения на основе itertools.groupby.

Каждый из них тестировался несколько раз (образцы), каждый образец, в свою очередь, вызывал несколько итераций функций. Я оценил минимальное, максимальное и стандартное отклонение для выборок.

Здесь мы идем, запуская пробный тест в 10 раз.

testing: thefourtheye, kroolik2, void, kroolik, alko, reed, visser
   10 samples
   10 iterations each
         author   min     avg     max    stddev
           reed 0.00000 0.00000 0.00000 0.00000
         visser 0.00000 0.00150 0.01500 0.00450
   thefourtheye 0.00000 0.00160 0.01600 0.00480
  thefourtheye2 0.00000 0.00310 0.01600 0.00620
           alko 0.00000 0.00630 0.01600 0.00772
           void 0.01500 0.01540 0.01600 0.00049
       kroolik2 0.04700 0.06430 0.07800 0.00831
        kroolik 0.32800 0.34380 0.37500 0.01716

Посмотрите внизу две строки: в этот момент решения kroolik были дисквалифицированы, так как с ним любое разумное количество образцов * итерации будут выполняться в течение нескольких часов. Здесь проходят финальные тесты. Я вручную добавил количество upvotes для ouptut:

testing: thefourtheye, kroolik2, void, kroolik, alko, reed, visser
   100 samples
  1000 iterations each
         author  upvotes   min     avg     max    stddev
           reed  [20]    0.06200 0.08174 0.15600 0.01841
   thefourtheye   [5]    0.06200 0.09971 0.20300 0.01911
         visser   [6]    0.10900 0.12392 0.23500 0.02263
  thefourtheye2          0.25000 0.29674 0.89000 0.07183
           alko  [11]    0.56200 0.62309 1.04700 0.08438
           void   [3]    1.50000 1.65480 2.39100 0.18721
        kroolik  [14]     [DSQ]

Ответ 4

Если заказ не имеет значения, вы можете использовать этот

original_list = [['a', 1], ['b', 1], ['a', 1], ['b', 1], ['b', 2], ['c', 2], ['b', 3]]
myDict = {}
for first, second in original_list:
    myDict[first] = myDict.get(first, 0) + second
result = [[key, value] for key, value in myDict.items()]
print result

Или вы можете использовать groupby, и код становится oneliner

original_list = [['a', 1], ['b', 1], ['a', 1], ['b', 1], ['b', 2], ['c', 2], ['b', 3]]
from itertools import groupby
print [[key, sum(item[1] for item in list(group))]
       for key, group in groupby(sorted(original_list), lambda x:x[0])]

Выход

[['a', 2], ['b', 7], ['c', 2]]

Ответ 5

Вы можете использовать collections.defaultdict:

original_list = [['a', 1], ['b', 1], ['a', 1], ['b', 1], ['b', 2], ['c', 2], ['b', 3]]
import collections
data = collections.defaultdict(list)
for item in original_list:
    data[item[0]].append(item[1])

output = {key: sum(values) for key, values in data.items()}
print output
# gives: {'a': 2, 'c': 2, 'b': 7}

Ответ 6

Я знаю, что это уродливо, но я немного повеселился, пытаясь реализовать его в 1 лайнере:

map(list, set(([(x[0], sum([i[1] for i in original_list if i[0]==x[0]])) for x in original_list])))

выход:

[['a', 2], ['b', 7], ['c', 2]]

Ответ 7

Возможно, вы тоже можете попробовать это,

>>> x = [[1,1],[2,2],[1,1],[2,2],[3,3],[4,4],[4,4]]
>>> z = []
>>> for i in x:
>>>    if i not in z:
>>>        z.append(i)
>>>
>>> z
[[1, 1], [2, 2], [3, 3], [4, 4]]