2015-09-19 8 views
7

Ich habe eine Liste von Tupeln, die jeweils zwei Elemente enthalten. Das erste Element von wenigen Unterlisten ist üblich. Ich möchte das erste Element dieser Unterlisten vergleichen und das zweite Element in einer Liste anhängen. Hier ist meine Liste:Das erste Element der aufeinanderfolgenden Listen von Tupeln in Python vergleichen

myList=[(1,2),(1,3),(1,4),(1,5),(2,6),(2,7),(2,8),(3,9),(3,10)] 

Ich mag würde eine Liste von Listen aus ihm machen, die etwa wie folgt aussieht: `

NewList=[(2,3,4,5),(6,7,8),(9,10)] 

Ich hoffe, wenn es eine effiziente Art und Weise ist.

+1

Was ist, wenn das erste Element einer Unter * Tupel * nicht üblich ist? Sie möchten ein Tupel aus einem einzelnen Element? –

+4

Das ist keine Liste von Listen, sondern eine Liste von Tupeln; das macht keinen Unterschied für Ihre Frage, aber dennoch sollten Sie sich des Unterschieds bewusst sein –

+0

Vielen Dank für die Korrektur. – PythonNoob

Antwort

6

Sie eine OrderedDict zur Gruppe durch die erste Teilelement jedes Tupel die Elemente verwenden können:

myList=[(1,2),(1,3),(1,4),(1,5),(2,6),(2,7),(2,8),(3,9),(3,10)] 

from collections import OrderedDict 

od = OrderedDict() 

for a,b in myList: 
    od.setdefault(a,[]).append(b) 

print(list(od.values())) 
[[2, 3, 4, 5], [6, 7, 8], [9, 10]] 

Wenn Sie wirklich Tupeln wollen:

print(list(map(tuple,od.values()))) 
[(2, 3, 4, 5), (6, 7, 8), (9, 10)] 

Wenn Sie nicht über die Reihenfolge scherte die Elemente erschienen und wollten nur die effizienteste Möglichkeit zur Gruppierung Sie könnten ein collections.defaultdict verwenden:

from collections import defaultdict 

od = defaultdict(list) 

for a,b in myList: 
    od[a].append(b) 

print(list(od.values())) 
Wenn Sie Ihre Daten, um nach Ihrem Eingabeb. also sind

Schließlich sortierte Sie einfach itertools.groupby zu einer Gruppe von dem ersten Teilelement aus jedem Tupel und extrahiert das zweite Element aus der gruppierten Tupel verwenden:

from itertools import groupby 
from operator import itemgetter 
print([tuple(t[1] for t in v) for k,v in groupby(myList,key=itemgetter(0))]) 

Ausgang:

[(2, 3, 4, 5), (6, 7, 8), (9, 10)] 

Auch die groupby wird nur funktionieren, wenn Ihre Daten um mindestens das erste Element sortiert ist.

Einige Timings auf einer vernünftigen Größe Liste:

In [33]: myList = [(randint(1,10000),randint(1,10000)) for _ in range(100000)] 

In [34]: myList.sort() 

In [35]: timeit ([tuple(t[1] for t in v) for k,v in groupby(myList,key=itemgetter(0))]) 
10 loops, best of 3: 44.5 ms per loop 

In [36]: %%timeit                od = defaultdict(list) 
for a,b in myList: 
    od[a].append(b) 
    ....: 
10 loops, best of 3: 33.8 ms per loop 

In [37]: %%timeit 
dictionary = OrderedDict() 
for x, y in myList: 
    if x not in dictionary: 
     dictionary[x] = [] # new empty list 
    dictionary[x].append(y) 
    ....: 
10 loops, best of 3: 63.3 ms per loop 

In [38]: %%timeit 
od = OrderedDict() 
for a,b in myList: 
    od.setdefault(a,[]).append(b) 
    ....: 
10 loops, best of 3: 80.3 ms per loop 

Iforder Angelegenheiten und die Daten sortiert, gehen Sie mit dem groupby, wird es noch näher an den defaultdict Ansatz, wenn es notwendig ist, um alle Elemente dem Tupel im Standarddict zuzuordnen.

Wenn die Daten nicht sortiert sind oder Sie sich nicht um eine Bestellung kümmern, finden Sie keinen schnelleren Weg zur Gruppierung als mit der defaultdict Methode.

+0

Danke Padraic, für den Code. Dies half mir, mein naives Problem zu lösen. – PythonNoob

+0

Warum unten zu diesem pythonischen Ansatz abstimmen ???? – Kasramvd

+0

einverstanden, dies ist wahrscheinlich der effizienteste Ansatz –

4

Dies fühlt sich an wie eine Aufgabe für ein Wörterbuch (wenn Sie Wörterbücher noch nicht kennen, suchen Sie sie auf python.org). Dies ist ein sehr ausführliches Beispiel, so ist es nicht, was ich in der täglichen Codierung schreiben würde, aber es ist besser, die ausführliche zu sein als unklar:

dictionary = collections.OrderedDict() 
for x, y in myList: 
    if not dictionary.has_key(x): 
     dictionary[x] = [] # new empty list 
    # append y to that list 
    dictionary[x].append(y) 
+0

Danke Marcus für den Vorschlag. Ich würde gerne über verschiedene Module von Python wissen, die mich mit Python fließend machen werden. Lassen Sie mich wissen, wenn Sie solche besseren Vorschläge haben. – PythonNoob

2

darüber nachgedacht hat, der effizienteste Ansatz ist dies wahrscheinlich ein -liner (unter der Annahme dictionary ist eine leere dict, dhdictionary = {} oder dictionary = OrderedDict() wie in Padraic' excellent answer):

for x,y in myList: dictionary.setdefault(x,[]).append(y) 

Ich sage nicht, dies der einfachste Ansatz zu lesen ist, aber ich mag es :)

EDIT Ha! Benchmarking hat mich falsch beurteilt; die setdefault Ansatz ist langsamer als der if not dictionary.has_key(x): dictionary[x]=[] Ansatz:

>>> timeit.timeit("for x,y in myList:\n if not dictionary.has_key(x):\n  dictionary[x]=[]\n dictionary[x].append(y)", "from collections import OrderedDict\nmyList=[(1,2),(1,3),(
1,4),(1,5),(2,6),(2,7),(2,8),(3,9),(3,10)]\ndictionary=OrderedDict()") 
2.2573769092559814 
>>> timeit.timeit("for x,y in myList: dictionary.setdefault(x,[]).append(y)", "from collections import OrderedDict\nmyList=[(1,2),(1,3),(1,4),(1,5),(2,6),(2,7),(2,8),(3,9),(3,10)]\ndictiona 
ry=OrderedDict()") 
3.3534231185913086 

Natürlich Padraic war noch recht: Auch seine defaultdict Ansatz nutzt aber 0.82s auf meiner Maschine, so dass es schneller um den Faktor 3.

, wie Padraic sagte: dict.has_key(x) ist veraltet, und man sollte stattdessen x in dict verwenden; Ich konnte jedoch keine Geschwindigkeitsdifferenz messen.

+0

'Nachdem Sie darüber nachgedacht haben, haben Sie auch * gemessen *? BTW: Warum "kopierst" du eine Antwort? – Wolf

+0

@Wolf: Ich beziehe mich darauf, nicht zu kopieren :) –

+0

Ja, aber das zu sagen, das ist * wahrscheinlich * der * effizienteste Ansatz * ein Kommentar wird ausreichen. – Wolf

1

Die folgenden sollte funktionieren:

import itertools 

myList = [(1,2),(1,3),(1,4),(1,5),(2,6),(2,7),(2,8),(3,9),(3,10)] 
print [tuple(x[1] for x in g) for k, g in itertools.groupby(myList, key=lambda x: x[0])] 

Welche zeigt:

[(2, 3, 4, 5), (6, 7, 8), (9, 10)] 
+0

Sorry, totaler Zufall. –

+0

möchte vielleicht erwähnen, dass die Daten in sortierter Reihenfolge sein müssen, zumindest so weit wie die ersten Elemente gehen –

Verwandte Themen