2016-07-15 9 views
0

einen Endpunkt auf meinem Backend Unter Berücksichtigung, dass die folgende Antwort zurück:Iterate Python-Liste und die Summe gleich Elemente

class Arc_Edges_Data(Resource): 
    def get(self): 
     #Connect to databse 
     conn = connectDB() 
     cur = conn.cursor() 
     #Perform query and return JSON data 
     try: 
      cur.execute("select json_build_object('source', start_location, 'target', end_location, 'frequency', 1) from trips") 
     except: 
      print("Error executing select") 
     ArcList = list (i[0] for i in cur.fetchall()) 
     return ArcList 

Die Frequenz hier soll immer von 1 für jede Reise. Also diese ArcList stammt eine Antwort wie folgt aus:

[ 
    { 
     "frequency": 1, 
     "source": "c", 
     "target": "c" 
    }, 
    { 
     "frequency": 1, 
     "source": "a", 
     "target": "b" 
    }, { 
     "frequency": 1, 
     "source": "a", 
     "target": "b" 
    }, ... 
] 

Wie kann ich diese Reaktion durchlaufen und die Elemente zusammenzufassen, die die gleiche source und target haben? In diesem Fall hätte die resultierende Liste nur ein Paar Quelle/Ziel mit "a" und "b", aber die Häufigkeit wäre 2 wegen der Summe.

Ich weiß, dass für Javascript ich etwas wie Array.reduce verwenden könnte, aber ich glaube nicht, dass es für Python existiert.

+0

Python hat zu reduzieren https://docs.python.org/2/library/functions.html#reduce – marcadian

+0

Python Counter kann Ihnen helfen: https://docs.python.org/3/library/collections.html#collections.Counter –

Antwort

2

Wie wäre es damit?

import collections 

data = [ 
    { 
     "frequency": 1, 
     "source": "c", 
     "target": "c", 
    }, 
    { 
     "frequency": 1, 
     "source": "a", 
     "target": "b", 
    }, 
    { 
     "frequency": 1, 
     "source": "a", 
     "target": "b", 
    }, 
] 

counter = collections.Counter() 

for datum in data: 
    counter[(datum['source'], datum['target'])] += datum['frequency'] 

print(counter) 

# Output: 
# Counter({('a', 'b'): 2, ('c', 'c'): 1}) 

Oh, wenn Sie die Daten wieder in das gleiche Format wieder setzen wollen, fügen Sie diesen Code:

newdata = [{ 
    'source': k[0], 
    'target': k[1], 
    'frequency': v, 
} for k, v in counter.items()] 

print(newdata) 

# Output: 
# [{'frequency': 1, 'target': 'c', 'source': 'c'}, {'frequency': 2, 'target': 'b', 'source': 'a'}] 
+0

Dies funktioniert perfekt! Aber ich habe auch gelesen, was @ Brendan Abel gesagt hat und welcher Weg für einen großen Datensatz am effizientesten ist? –

+0

@ Shoplifter.Doe Ich habe ihre Leistung nicht getestet, aber meine Vermutung ist, dass sie sehr ähnlich sind. – smarx

+0

Ok danke, ich kann immer einen Scheck in die andere Richtung zurückkommen, wenn ich es brauche. –

0

Sie können dies tun:

r = {} 
for d in ArcList: 
    key = (d['source'], d['target']) 
    r[key] = r.setdefault(key, 0) + d['frequency'] 
return [{'source': k[0], 'target': k[1], 'frequency': v} for k, v in r.items()] 

Wenn Sie möchten, bewahren Sie die ursprüngliche Reihenfolge der Artikel:

from collections import OrderedDict 
r = OrderedDict() 
# The rest of the solution is the same 
... 
+0

Dies entspricht meiner Antwort, aber mit einem 'dict' anstelle eines' Counter'. (Ich persönlich bevorzuge 'Counter', nur weil die Absicht des Codes klarer ist, aber mit dieser Antwort ist nichts falsch.) – smarx

+0

@smarx Ja, ich dachte an Counter, aber es funktioniert nicht wirklich, wenn' frequency' nicht ist t t immer 1. Du verwendest im Grunde nur Counter wie ein normales dict, obwohl es nett ist, dass es wie ein 'defaultdict' funktioniert ohne die Notwendigkeit von' setdefault' –

+0

Was meinst du mit "es funktioniert nicht wirklich wenn" Frequenz "ist nicht immer 1?" – smarx

Verwandte Themen