2016-07-20 24 views
0

Ich habe eine Liste von Wörterbuch enthält Listen mit:Python Liste der Wörterbücher Listen Verständnis

a = [{'alpha': 'a', 'val': 10, 'num': ['one', 'two']}, 
    {'alpha': 'b', 'val': 22, 'num': ['two']}, 
    {'alpha': 'c', 'val': 1, 'num': ['seven']}, 
    {'alpha': 'a', 'val': 10, 'num': ['three','nine']}, 
    {'alpha': 'b', 'val': 9, 'num': ['two', 'four']}] 

Der Ausgang ich will, ist:

[{'alpha': 'a', 'TotalVal': 20, num: ['one', 'two', 'three', 'nine'], 'numlen': 4}, 
{'alpha': 'b', 'TotalVal': 31, num: ['two', 'four'], 'numlen': 2}, 
{'alpha': 'c', 'val': 1, 'num': ['seven'], 'numlen': 1}] 

Ich habe versucht, die folgenden:

sumVal = collections.defaultdict(float) 
for info in a: 
    sumVal[info['alpha']] += info['val'] 

sumVal = [{'alpha': c, 'TotalVal': sumVal[c]} for c in sumVal] 

numList = collections.defaultdict(list) 
for info in a: 
    numList[info['alpha']].append(info['num']) 
numList = [{'alpha': k, 'num': set(v), 'len': len(set(v))} for k, v in numList.items()] 

def merge_lists(l1, l2, key): 
    merged = {} 
    for item in l1+l2: 
     if item[key] in merged: 
      merged[item[key]].update(item) 
     else: 
      merged[item[key]] = item 
    return [val for (_, val) in merged.items()] 

final = merge_lists(sumVal, numList, 'alpha') 

Ich bekomme nicht die gewünschte Ausgabe für numList. Erhalte den folgenden Fehler.

TypeError: unhashable type: 'list'

Wie kann ich die gewünschte Ausgabe in weniger Schritten erhalten und den Fehler loswerden?

+1

Mögliche Duplikat [Python-Wörterbuch: Typeerror: unhashable Typ: 'list'] (http://stackoverflow.com/questions/8532146/python-dictionary-typeerror-unhashable-type-list) –

+1

können Sie erklären, was Ihre korrekte Ausgabe sein soll. Zeigen Sie auch vollständige Rückverfolgung in Ihrer Frage –

+0

@joelgoldstick Ich habe es erwähnt, die zweite Liste von oben sollte die endgültige Ausgabe sein. – Blabber

Antwort

1

Versuchen Sie diesen Code:

a = [{'alpha':'a','val':10,'num':['one','two']},{'alpha':'b','val':22,'num':['two']},{'alpha':'c','val':1,'num':['seven']},{'alpha':'a','val':10,'num':['three','nine']},{'alpha':'b','val':9,'num':['two','four']}] 

def merge_dicts(x, y): 
    x.update(y) 
    return x 

def r(acc, x): 
    if x['alpha'] in acc: 
     acc[x['alpha']]['TotalVal'] += x['val'] 
     acc[x['alpha']]['num'] |= set(x['num']) 
     acc[x['alpha']]['numlen'] = len(acc[x['alpha']]['num']) 
    else: 
     acc[x['alpha']] = { 
      'TotalVal': x['val'], 
      'num': set(x['num']), 
      'numlen': len(set(x['num'])), 
     } 
    return acc 

result = map(lambda (x, y): merge_dicts({'alpha': x}, y), 
      reduce(r, a, {}).iteritems()) 
print(result) 
+0

Das Num-Ding sollte mir verschiedene Werte geben (set) und numlen die Länge des Satzes in der endgültigen Ausgabe. Der Code ist jedoch ein guter Anfang. Danke :) – Blabber

+0

Welche Änderung kann ich an Ihrem Code dafür machen? – Blabber

+0

@front, dies gibt die Ausgabe: [{'alpha': 'a', 'TotalVal': 20, 'num': set (['drei', 'neun', 'zwei', 'eins']), 'numlen': 4}, {'alpha': 'c', 'Gesamtwert': 1, 'num': set (['sieben']), 'numlen': 1}, {'alpha': 'b' , 'TotalVal': 31, 'num': set (['vier', 'zwei']), 'numlen': 2}]. - ein Element (alle Liste) im Set! –

1

Das Problem in dieser Linie ist:

numList[info['alpha']].append(info['num']) 

eine Liste auf einer Liste angehängt, legt die Liste, die Sie in der Liste anhängen Sie Anhängen an .

Ich denke, was Sie wollen, ist zu erweitern.

append vs. extend

+0

Extend gibt auch nicht die gewünschte Ausgabe. Versuchte das! – Blabber

+0

Alle richtigen Daten sind vorhanden, wenn Sie extend verwenden. Aber es ist in einer anderen Reihenfolge als Ihre erwartete Ausgabe. Denken Sie daran, Wörterbücher sind nicht bestellt, so dass es Dinge außer Betrieb setzen wird. – beauxq

+0

Es funktioniert für dieses Beispiel, aber nicht für andere irgendwie. – Blabber

1
#!/usr/bin/env python 

a = [{'alpha':'a','val':10,'num':['one','two', 'one', 'two']},{'alpha':'b','val':22,'num':['two']},{'alpha':'c','val':1,'num':['seven']},{'alpha':'a','val':10,'num':['three','nine']},{'alpha':'b','val':9,'num':['two','four']}] 


def merge_lists(src, key): 
    merged = {} 
    for i in src: 
     _key = i[key] 
     if _key in merged: 
      merged[_key]['TotalVal'] += i['val'] 
      merged[_key]['num'].extend(i['num']) 
      merged[_key]['num'] = list(set(i['num'])) 
      merged[_key]['numlen'] = len(merged[_key]['num']) 
     else: 
      merged[_key] = {'TotalVal': i['val'], 'alpha': i['alpha'], 'num': i['num'], 'numlen': 1} 

    return [val for (_, val) in merged.items()] 


final = merge_lists(a, 'alpha') 

print(final) 

Output: [{ 'alpha': 'a', 'TotalVal': 20 'num' [ 'neun', 'drei'], 'numlen': 2 }, {'alpha': 'c', 'Gesamtwert': 1, 'num': ['sieben'], 'numlen': 1}, {'alpha': 'b', 'TotalVal': 31, ' num ': [' vier‘, 'zwei'], 'numlen': 2}]

+0

die endgültige num sollte verschiedene Einträge enthalten, die nummern von b 2 bilden. Der Beitrag war jedoch eine große Hilfe! – Blabber

+0

Welche Änderung kann ich an Ihrem Code dafür vornehmen? – Blabber

+1

@Blabber, verwenden Sie 'list (set (i [' num ']))' zum Entfernen von Duplikaten. –

1

Nicht so kurz wie andere Antworten, aber einfach in der Implementierung

a = [{'alpha':'a','val':10,'num':['one','two']}, 
    {'alpha':'b','val':22,'num':['two']}, 
    {'alpha':'c','val':1,'num':['seven']}, 
    {'alpha':'a','val':10,'num':['three','nine']}, 
    {'alpha':'b','val':9,'num':['two','four']}] 

new_list = [] 

# Loop through entries 
for entry in a: 
    # Store first entries 
    if entry['alpha'] not in [i['alpha'] for i in new_list]: 
     new_dict = {'alpha': entry['alpha'], 
        'TotalVal': entry['val'], 
        'num': entry['num'], 
        'numlen': len(entry['num'])} 
     new_list.append(new_dict) 
     continue 

    # Add in additional entries 
    for i, n in enumerate(new_list): 
     if n['alpha'] == entry['alpha']: 
      entry_vals = entry.values() 
      new_list[i]['TotalVal'] = new_list[i]['TotalVal'] + entry['val'] 
      new_list[i]['num'] = new_list[i]['num'] + entry['num'] 
      new_list[i]['numlen'] = len(new_list[i]['num']) 

# filter final data 
for i, n in enumerate(new_list): 
    # Remove duplicate entries in num 
    for entry in n['num']: 
     if n['num'].count(entry) > 1: 
      new_list[i]['num'].remove(entry) 

    # Update numlen 
    new_list[i]['numlen'] = len(new_list[i]['num']) 

print new_list 
1

Hier ist die einfachste Lösung, die ich kam mit:

a = [{'alpha':'a','val':10,'num':['one','two']}, 
    {'alpha':'b','val':22,'num':['two']}, 
    {'alpha':'c','val':1,'num':['seven']}, 
    {'alpha':'a','val':10,'num':['three','nine']}, 
    {'alpha':'b','val':9,'num':['two','four']}] 

a2 = [] 
alphas = set(d['alpha'] for d in a) 
for alpha in alphas: 
    TotalVal, num, numlen = 0, set(), 0 
    for d in a: 
     if d['alpha'] == alpha: 
      TotalVal += d['val'] 
      num = num | set(d['num']) 
      numlen += 1 
    new_dict = {'alpha': alpha, 'num': list(num), 'numlen': numlen} 
    if numlen > 1: 
     new_dict['TotalVal'] = TotalVal 
    else: 
     new_dict['val'] = TotalVal 
    a2.append(new_dict) 

Demo:

>>> for d in a2: print(d) 
{'alpha': 'a', 'num': ['three', 'nine', 'two', 'one'], 'numlen': 2, 'TotalVal': 20} 
{'alpha': 'c', 'num': ['seven'], 'numlen': 1, 'val': 1} 
{'alpha': 'b', 'num': ['four', 'two'], 'numlen': 2, 'TotalVal': 31} 
Verwandte Themen