2016-05-15 8 views
0

Ich habe eine Funktion, die alle Kombinationen von Listenelementen schafft, was diese als eine Liste von Listen:Python - wiederum eine Kombinationsfunktion in einen Generator

def makeCombos(arr): 
    yield (sum([map(list, combinations(arr, i)) for i in range(len(arr) + 1)], [])) 

makeCombos([1,2,3,4,5]) Aufruf gibt mir ein Generator-Objekt, sondern ruft .next() gibt mir nicht eine Combo auf einmal, es gibt mir die ganze Liste der Combos.

Wie kann ich dies in eine Generatorfunktion verwandeln, die ich anrufen kann?

+0

also wollen Sie die Kraft von 'arr' ?, gibt es ein Rezept dafür in [Itertools Rezepte] (https://docs.python.org/3/library/itertools.html#ieiterTools-recipes) – Copperfield

Antwort

3

sum(iterable, []) erstellt keine Liste von Listen. Es flacht die Dinge tatsächlich ab.

yield (sum(...)) In dieser Zeile geben Sie nur ein einzelnes Element, die abgeflachte Liste aller Kombinationen.

Für Python 2.X sum([(map(list, combinations(arr, i))) ...]) wird funktionieren, aber in Python 3.X map gibt nicht mehr eine Liste zurück. Stattdessen wird ein Kartenobjekt zurückgegeben. Also, wenn Anyones auf Python 3.X einfach in list(map(.....)) um dies auf 3.X.

Ich denke, was Sie eigentlich wollen so etwas wie dieses:

from itertools import combinations 
def makeCombos(arr): 
    for i in range(len(arr) + 1): 
     for combo in map(list, combinations(arr, i)): 
      yield combo 

#Or call next 

combos = makeCombos([1, 2, 3, 4, 5]) 
for combo in combos: 
    print combo 

Eine Alternative aus dem Kommentar (e) für einen Einzeiler:

Stattdessen wir nachgeben können Rückkehr einen Generator Objekt und Zyklus durch, genau wie wir mit der yield.

z.B. -

from itertools import combinations 

def makeCombos(arr): 

    return (combo for i in range(len(arr) + 1) for combo in map(list, combinations(arr, i))) 

combos = makeCombos([1, 2, 3, 4, 5]) 
.... 

Für dieses Sein "Pythonic" würde ich nicht wirklich so sagen. Ich bevorzuge eigentlich die verschachtelte Forloop, die bei weitem besser lesbar ist.

Obwohl, können wir immer noch versuchen, es etwas mehr/compact aufzuräumen es durch ein paar „Tricks“ zu tun

from itertools import combinations as cs #or some other name) 

def makeCombos(arr): 

    return (c for i in range(len(arr) + 1) for c in map(list, cs(arr, i))) 

Aber jetzt hast du alle Lesbarkeit verloren und das sieht aus wie etwas würden Sie siehe in Perl. (Das Grauen!)

Ausgang:

[] 
[1] 
[2] 
[3] 
[4] 
[5] 
[1, 2] 
[1, 3] 
[1, 4] 
[1, 5] 
[2, 3] 
[2, 4] 
[2, 5] 
[3, 4] 
[3, 5] 
[4, 5] 
[1, 2, 3] 
[1, 2, 4] 
[1, 2, 5] 
[1, 3, 4] 
[1, 3, 5] 
[1, 4, 5] 
[2, 3, 4] 
[2, 3, 5] 
[2, 4, 5] 
[3, 4, 5] 
[1, 2, 3, 4] 
[1, 2, 3, 5] 
[1, 2, 4, 5] 
[1, 3, 4, 5] 
[2, 3, 4, 5] 
[1, 2, 3, 4, 5] 
+0

Mit einem Namen wie Pythonista, wie kann ich streiten? Haha. Eine Frage: Gibt es eine mehr "pythonische", "einzeilige" Art, die verschachtelte For-Schleife anzugeben? –

+0

Siehe die Bearbeitung :) – Pythonista

+0

'def makeCombos (arr): zurück (Combo für i in Bereich (len (arr) + 1) für Combo in der Karte (Liste, Kombinationen (arr, i)))'. Ja, 'Rückkehr'. Das heißt, verwandle das Doppelverständnis direkt in einen Generator. – alexis

1

itertools hat bereits ein Verfahren zum Verbinden Iterables zusammen: es chain genannt wird. Was Sie wollen, ist etwas wie das Folgende:

Einfach, kurz und ziemlich Pythonic meiner Meinung nach.

+1

anstatt eine Liste zu erstellen, besser verwenden Sie 'chain.from_iterable' – Copperfield

+0

@Copperfield Danke, ich werde die Antwort bearbeiten. – amiller27

+1

@Atsch Ich glaube, die Frage war nach Kombinationen gefragt, nicht nach Permutationen. Ich sehe nicht, wie Permutationen hier helfen würden – amiller27