Как объединить несколько кодов с одним и тем же значением ключа? - PullRequest
0 голосов
/ 04 ноября 2019

У меня есть список пар dicts / key-value, таких как:

list = [{'mid': 123, 'msg': 'sometext', 'antivirus': 'positive'},
        {'mid': 123, 'msg': 'sometext2', 'antivirus': 'positive'},
        {'mid': 456, 'msg': 'sometext3', 'antivirus': 'positive'},
        {'mid': 456, 'msg': 'sometext4', 'antivirus': 'positive'},
        {'mid': 789, 'msg': 'sometext5', 'antivirus': 'positive'}]

Я хочу, чтобы результатом стал новый список dict (наиболее эффективным способом, если это возможно), сгруппировав их по значениюклавиши ' mid ':

result = [{'mid': 123, 'msg': 'sometext,sometext2', 'antivirus': 'positive,positive'}, 
          {'mid': 456, 'msg': 'sometext3,sometext4', 'antivirus': 'positive,positive'},
          {'mid': 789, 'msg': 'sometext5', 'antivirus': 'positive'}]

Ответы [ 4 ]

0 голосов
/ 04 ноября 2019

(список - это ключевое слово в python, поэтому я изменил имя на mylist) Вот ваш обязательный однострочный:

import itertools; map(lambda sub: reduce(lambda a,b: { key : ",".join(set(filter(lambda x: x!='', [str(a.get(key, ''))] + [str(b.get(key, ''))]))) for key in set(a.keys() + b.keys()) }, sub, {}), map(lambda sub: list(sub[1]), itertools.groupby(mylist, lambda lst: lst['mid'])))

менее неприятно:

import itertools
groups = map(lambda sub: list(sub[1]), itertools.groupby(mylist, lambda lst: lst['mid'])) # get the dicts organized into groups on key 'mid'

def joindicts(a,b):
    result = dict()
    for key in set(a.keys() + b.keys()): # get union of keys for both dicts
        val_a = str(a.get(key, ''))
        val_b = str(b.get(key, ''))
        val = ','.join([x for x in [val_a] + [val_b] if x != ''])
        result.update({key:val})
    return result

map(lambda sub: reduce(joindicts, sub, {}), groups)
0 голосов
/ 04 ноября 2019

Вы можете просто использовать pandas dataFrame:

import pandas as pd

lst  = [{'mid': 123, 'msg': 'sometext', 'antivirus': 'positive'},
        {'mid': 123, 'msg': 'sometext2', 'antivirus': 'positive'},
        {'mid': 456, 'msg': 'sometext3', 'antivirus': 'positive'},
        {'mid': 456, 'msg': 'sometext4', 'antivirus': 'positive'},
        {'mid': 789, 'msg': 'sometext5', 'antivirus': 'positive'}]

d = (pd.DataFrame(lst)
       .groupby(['mid'])
       .agg(','.join)
       .reset_index()
       .to_dict('r'))

print (d)

, вывод:

[{'mid': 123, 'antivirus': 'positive,positive', 'msg': 'sometext,sometext2'}, 
 {'mid': 456, 'antivirus': 'positive,positive', 'msg': 'sometext3,sometext4'}, 
 {'mid': 789, 'antivirus': 'positive', 'msg': 'sometext5'}]
0 голосов
/ 04 ноября 2019

Плохо было бы называть одну из ваших переменных (list) такой же, как встроенную, поэтому я использую l здесь

, используя промежуточный defaultdict:

from collections import defaultdict


intermediate = defaultdict(lambda: defaultdict(list))
for record in l:
    mid = record["mid"]
    for key, value in record.items():
        if key == "mid":
            continue
        intermediate[mid][key].append(value)

result = [
    {"mid": mid, **{key: ",".join(value) for key, value in attributes.items()}}
    for mid, attributes in intermediate.items()
]
result
0 голосов
/ 04 ноября 2019

Не в восторге от такого подхода, но он вас туда доставит. Он перебирает список диктов lst, используя defaultdict для группировки по значению mid, затем перебирает , что , для получения выходных данных, объединяя значения msg и antivirus ключи.

from collections import defaultdict

lst = [{'mid': 123, 'msg': 'sometext', 'antivirus': 'positive'},
       {'mid': 123, 'msg': 'sometext2', 'antivirus': 'positive'},
       {'mid': 456, 'msg': 'sometext3', 'antivirus': 'positive'},
       {'mid': 456, 'msg': 'sometext4', 'antivirus': 'positive'},
       {'mid': 789, 'msg': 'sometext5', 'antivirus': 'positive'}]

dd = defaultdict(list)
for d in lst:
    key = d['mid']
    dd[key].append(d)

output = []
for (k,v) in dd.items():
    output.append({
        'mid':       k,
        'msg':       ','.join(x['msg']       for x in v),
        'antivirus': ','.join(x['antivirus'] for x in v),
    })

print(output)
[
  {'mid': 123, 'msg': 'sometext,sometext2', 'antivirus': 'positive,positive'}, 
  {'mid': 456, 'msg': 'sometext3,sometext4', 'antivirus': 'positive,positive'}, 
  {'mid': 789, 'msg': 'sometext5', 'antivirus': 'positive'}
]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...