2016-04-24 7 views
-2

Ich habe einen Algorithmus implementiert, um ein kartesisches Produkt von beliebig verschachtelten Dicts in Python zu erstellen. Die Felder in der Root-Ebene müssen in mehreren Zeilen repliziert werden, da auch Arrays darin verschachtelt sein können. Ich habe die itertools.product rekursiv, aggregierende Zwischen-Iteratoren verwendet.Clean dynamisch erzeugte verschachtelte Tupel

Es funktioniert, aber das Problem ist das Auspacken im Finale. Ich endete mit einer Struktur wie folgt:

(11, 12.2, 123.2, 1.23, 104.75, (10.7, 104.75, 104.75, ('N', True, False, 'B2B'), 99.01, 6.3, 1.23, 5.87, 12.2), 1, 'SP', 7).

Ich suche nach einer Liste Verständnis oder einen Generator Ausdruck oder sogar einem ausgewachsenen Generator, der flach und reinigen Sie diese Zeile:

(11, 12.2, 123.2, 1.23, 104.75, 10.7, 104.75, 104.75, 'N', True, False, 'B2B', 99.01, 6.3, 1.23, 5.87, 12.2, 1, 'SP', 7).

Was ist der beste und schnellste Weg, es zu tun?

EDIT

Eigentlich, was ich gefragt habe, ist eine Liste Verständnis oder ein Generator Ausdruck oder sogar ein vollständiger geblasener Generator, weil ich es in einem Haken umfassen müssen, die Ausgabe der itertools.product abfängt selbst. Ich brauche nicht einfach einen Weg, um diese Tuples zu reinigen. So ist es ist kein ein Duplikat.

Leute, bitte, ich WILL keine rekursive Funktion dafür! Ich habe eine Klasse, deren __iter__()-Methode eine itertools.product einer dynamisch generierten Daten zurückgibt. Ich versuche, entweder von diesen:

  1. diese Methode Ändern Sie die interne Tupel zu handhaben:

    class Explosion: 
        ... 
        def __iter__(self): 
         return product(*self.fragments) 
    
  2. Encapsulate in einem anderen Objekt die Umwandlung der Handhabung, aber das ist weniger wünschenswert:

    class CleanOutput: 
        def __init__(self, it): 
         self.it = it 
    
        def next(self): 
         for x in self.it: 
          yield ? 
    
    class Explosion: 
        ... 
        def __iter__(self): 
         return CleanOutput(product(*self.fragments)) 
    
+0

Können Sie Ihren Code zeigen, dass, wie Sie mit dem ersten erzielt Ergebnis? – Kasramvd

+0

Sorry @Kasramvd, kann ich nicht. Aber es ist nicht so komplex, es ist ein einfacher _flatten dict_ -Algorithmus, mit ein paar Drehungen, wie das Erkennen, wenn man eine Sequenz in der Hand hat, ein Element davon auslesen und ausprobieren und, wenn es Primitive sind, sie speichern, um verwendet zu werden Wenn es sich bei itertools.product um ein geschachteltes Diktat handelt, ist es schwieriger, da Sie für jeden der Einträge ein weiteres Explosionsobjekt wie das Root-Objekt erstellen müssen.Dann kombinieren Sie diese Produkte (die verschachtelten Tupel) durch Verketten der Listen und wenden das äußere Produkt damit an. – rsalmei

+0

Um ehrlich zu sein, verstehe ich nicht, was Sie davon abhält, die am höchsten bewertete Antwort von der verlinkten Seite zu verwenden. 'product' gibt einen Iterator zurück, den Sie an die Funktion senden und den resultierenden Generator wie' return flatten (product (...)) zurückgeben können ' – vaultah

Antwort

0
def gen(data): 
    for item in data: 
     if isinstance(item, tuple): 
      for nested in gen(item): 
       yield nested 
     else: 
      yield item 

Unteste d, sollte aber funktionieren.

+0

Nein, aber danke. Denken Sie daran, dass itertools.product() Tupel als die verschiedenen Kombinationen zurückgibt, und ich WÜNSCHE diese Kombinationen nur ohne die inneren Tupel. Alles, was ich bekam, waren Dutzende von getrennten Ints oder Strings, ohne die Grenzen der Kombinationen. – rsalmei

+0

@rsalmei Sie sagen also, Sie wollen keinen Generator? – Natecat

+0

Nein, ich möchte einen Generator! Das ist, was ich gefragt habe: Listenverständnis oder ein Generatorausdruck ... Ich muss nur die inneren Tupel entfernen, nicht die Kombinationen. – rsalmei

1

Das war nicht einfach, die Rekursion muss verwendet werden, aber getrennt von der Haupt __iter__ Methode. So habe ich es gemacht. Jetzt auch mit einem rekursiven Generator _merge, von einem anderen Generator genannt _flatten:

class Explosion: 
    # ... 

    def __iter__(self): 
     def _flatten(container): 
      def _merge(t): 
       for te in t: 
        if isinstance(te, tuple): 
         for ite in _merge(te): 
          yield ite 
        else: 
         yield te 

      for t in container: 
       yield tuple(_merge(t)) 

     return _flatten(product(*self.fragments)) 

ein Beispiel für die Anwendung der _flatten() Funktion Siehe:

>>> list(itertools.product([1,2],[3,(4,(5,6))])) 
[(1, 3), (1, (4, (5, 6))), (2, 3), (2, (4, (5, 6)))] 
>>> list(_flatten(itertools.product([1,2],[3,(4,(5,6))]))) 
[(1, 3), (1, 4, 5, 6), (2, 3), (2, 4, 5, 6)] 
+1

Wenn Sie möchten, können Sie auch die '_flatten' Hilfsmethode * innerhalb * Ihrer' __iter__' Methode verschachteln, falls Sie sie nicht benötigen irgendwo anders. –

+0

Das ist cool @ByteCommander, danke! – rsalmei

+0

@ByteCommander, Ich habe versucht, die 'Merge' Helfer-Methode einen zweiten Generator, innerhalb der _flatten-Generator, aber es funktioniert nicht, die externen Tupel (diejenigen, die ich pflegen will) kam leer. Weißt du, warum? Ich würde lieber nicht eine temporäre Sequenz verwenden, um Tonnen von Daten zu bewegen, aber ... – rsalmei

Verwandte Themen