2016-03-15 3 views
0

У меня есть список словарей, как:Удаление дубликатов в списке словарей

dict_list = [ 
    {"Module": abc, "Error": dgh, "Count": 12, Time: "kabs"}, 
    {"Module": abc, "Error": dgh, "Count": 3, Time: "askdj"}, 
    {"Module": aea, "Error": adsaw, "Count": 4, Time: "asna" 
] 

Как вы можете видеть каждый словарь имеет те же уникальные ключи, но одинаковые или разные значения. Могут быть случаи, когда значения dict2["Modules"] == dict1["Modules"] и dict2["Errors"] == dict1["Errors"] с другими значениями ключа различны, как показано в примере. Этот экземпляр называется дубликатом. Я хочу удалить дубликат словаря из списка, но увеличить счетчик оставшегося.

+4

Вы достаточно хорошо описали свою цель. Что именно удерживает вас от вашей цели? что ты уже испробовал? Как это не удалось? –

+1

также, когда вы отправляете фиктивные данные, постарайтесь сделать это в соответствии с вашими потребностями, потому что подсчет строк со значениями не является лучшим примером. –

+0

Было бы неплохо включить пример вывода. В текущем вопросе мы не знаем, какое (если либо) время нужно сохранить. –

ответ

0

Возможно, это сработает.

no_duplicates = {} 
for d in dict_list: 
    # Generate your unique key 
    k = (d["Module"], d["Error"]) 
    try: 
     # Add if already exists. 
     no_duplicates[k]["Count"] += 1 
    except KeyError: 
     # Create a new one if not. 
     no_duplicates[k] = d 
     d["Count"] = 1 

# Generate the new list (Works for python 2 and 3) 
no_duplicates_list = list(no_duplicates.values()) 

Вы создаете новый словарь не дубликатов и сделать ключ значения, которые вы хотите, чтобы не иметь дубликатов. Например, (d["Module"], d["Error"]). Затем, если он уже существует, вы увеличиваете счет. Если нет, вы создаете новую запись в словаре.

Однако, если у вас есть больше новых ключей, чем дублей, это будет более эффективным, как будет выброшено меньше исключений:

no_duplicates = {} 

for d in dict_list: 
    k = (d["Module"], d["Error"]) 
    # Set count to 0 
    d["Count"] = 0 
    # Set and increase count at once 
    no_duplicates.setdefault(k, d)["Count"] += 1 

no_duplicates_list = list(no_duplicates.values()) 

UPDATE:

Если вы не хотите сбросить подсчитывать, вот код:

no_duplicates = {} 

for d in dict_list: 
    # Generate your unique key 
    k = (d["Module"], d["Error"]) 
    try: 
     # Add if already exists. 
     no_duplicates[k]["Count"] += d["Count"] 
    except KeyError: 
     # Create a new one if not. 
     no_duplicates[k] = d 

# Generate the new list (Works for python 2 and 3) 
no_duplicates_list = list(no_duplicates.values()) 

или

no_duplicates = {} 

for d in dict_list: 
    k = (d["Module"], d["Error"]) 
    # Set and increase count at once 
    no_duplicates.setdefault(k, d)["Count"] += 1 

no_duplicates_list = list(no_duplicates.values()) 
+1

Это просто увеличивает значение 'Count' на 1, а не суммирует их. –

+0

@JaredGoguen Обновлен мой ответ. – Bharel

1

С данной информацией эта проблема является только неполной. Если то, что содержится в ключах Module и Error, хешируется (например, строки), их можно использовать в качестве ключа словаря. Вы можете создать промежуточный словарь с кортежем (Module, Error) как уникальный ключ и проверить его существование. Если он не существует, сохраните словарь. Если он действительно существует, приращение Count. Затем значения этого словаря будут содержать уникальные записи исходного списка с накопленными счетами.

def merge_and_sum_counts(list_of_dictionaries): 
    tupled_dictionary = {} 

    for d in list_of_dictionaries: 
     key = (d['Module'], d['Error']) 

     if key not in tupled_dictionary: 
      tupled_dictionary[key] = d 
     else: 
      tupled_dictionary[key]['Count'] += d['Count'] 

    return tupled_dictionary.values() 

Обратите внимание, что эта функция не заботится о том, что Time остается в каждом словаре (так как вы не упоминать об этом). Пример использования приведен ниже.

list_of_dictionaries = [ 
    {'Module': 'A', 'Error': 'A', 'Count': 5, 'Time': '22:34'}, 
    {'Module': 'A', 'Error': 'A', 'Count': 3, 'Time': '21:33'}, 
    {'Module': 'A', 'Error': 'B', 'Count': 2, 'Time': '15:31'}, 
    {'Module': 'B', 'Error': 'A', 'Count': 1, 'Time': '07:59'}, 
    {'Module': 'B', 'Error': 'A', 'Count': 7, 'Time': '10:45'}, 
    {'Module': 'B', 'Error': 'B', 'Count': 9, 'Time': '15:45'}, 
] 

print merge_and_sum_counts(list_of_dictionaries) 

# [{'Count': 8, 'Time': '07:59', 'Module': 'B', 'Error': 'A'}, 
# {'Count': 2, 'Time': '15:31', 'Module': 'A', 'Error': 'B'}, 
# {'Count': 8, 'Time': '22:34', 'Module': 'A', 'Error': 'A'}, 
# {'Count': 9, 'Time': '15:45', 'Module': 'B', 'Error': 'B'}] 

Также обратите внимание, что это помещает существующие словарные объекты в новый список. Смысл, словари в исходном списке будут обновлены после запуска этой функции. Чтобы этого избежать, вы можете изменить tupled_dictionary[key] = d на tupled_dictionary[key] = d.copy().

Этот подход может также работать, если Module и Error не хешируются, потому что сами кортежи. Тем не менее, вы захотите убедиться, что Module1 == Module2 возвращает значение, которое вы ожидаете. Если Module не переопределяет функцию класса по умолчанию, то равенство существует только до объекта id. (Что может быть то, что вы хотите, трудно сказать.)

1

Я считаю, что это то, что вам нужно:

no_duplicates = {} 
for d in dict_list: 
    k = (d["Module"], d["Error"]) 

    if k in no_duplicates: 
     no_duplicates[k]["Count"] += d['Count'] 
    else: 
     no_duplicates[k] = d # or d.copy() if you need to keep d untouched 

no_duplicates = no_duplicates.values() 
+0

Я думаю, что должно быть обсуждение о том, предпочтительнее ли «ключ» или «ключ не в». –

+0

Я бы использовал 'not in', если бы мне пришлось изменить d, прежде чем устанавливать его как значение k, но в этом случае мы увеличиваем счетчик на k уже присутствующий, следовательно, мой подход. Я только что добавил 'd.copy()', потому что мне также интересно, нужно ли ему сохранять свои начальные значения списка. –

+0

Однако, как мы оба отвечали в то же время, но вы отвечаете более подробно, я бы рекомендовал OP проголосовать за вас, но использовать мой if/else ;-) –

-1
list_d = [{"Module":'abc',"Error":'dgh',"Count":'fff','Time':"kabs"}, 
    {"Module":'abc',"Error":'dgh',"Count":'adak','Time':"askdj"}, 
    { "Module":'aea',"Error":'adsaw',"Count":'asa','Time':"asna"}] 
no_duplicate = {} 

for index, d in enumerate(list_d): 
    key = d['Module'].lower() +'-'+ d['Error'].lower() 
    if key not in no_duplicate: 
     no_duplicate[key] = [index,1] 
    else: 
     no_duplicate[key][1] += 1 

output = [] 
for key,value in no_duplicate.items(): 
    index = value[0] 
    count = value[1] 
    if count >=2: 
     list_d[index]['count'] = count 
    output.append(list_d[index]) 
print output 
0

Вы также можете посмотреть на панд, потому что вы хотите, почти база данных ОПЕРАЦИЯ:

с:

dict_list=[{'Time': 'kabs', 'Count': 12, 'Error': 1, 'Module': 1}, 
{'Time': 'askdj', 'Count': 3, 'Error': 1, 'Module': 1}, 
{'Time': 'asna', 'Count': 4, 'Error': 2, 'Module': 2}] 

pandas.DataFrame(dict_list).groupby(['Module','Error'])['Count'].sum() дает:

Module Error 
1  1  15 
2  2   4 
Смежные вопросы