Kann eine Python-Funktion einen Generator nehmen und Generatoren auf Teilmengen ihrer erzeugten Ausgabe zurückgeben?

StackOverflow https://stackoverflow.com/questions/1215464

  •  06-07-2019
  •  | 
  •  

Frage

Lassen Sie uns sagen, dass ich eine Generatorfunktion wie folgt aussehen:

import random
def big_gen():
  i = 0
  group = 'a'
  while group != 'd':
    i += 1
    yield (group, i)
    if random.random() < 0.20:
      group = chr(ord(group) + 1)

Beispiel Ausgabe könnte so aussehen: ( 'A', 1), ( 'a', 2), ( 'a', 3), ( 'a', 4), ( 'a', 5), ( 'a', 6), (‘ a‘, 7), ( 'a', 8), ( 'b', 9), ( 'C', 10), ( 'C', 11), ( 'C', 12), (c ' , 13)

Das möchte ich in drei Gruppen brechen: Gruppe A, Gruppe B und Gruppe C Und ich würde für jede Gruppe einen Generator mögen. Dann würde ich den Generator und den Gruppenbuchstaben in eine Unterfunktion übergeben. Ein Beispiel für die Unterfunktion:

def printer(group_letter, generator):
  print "These numbers are in group %s:" % group_letter
  for num in generator:
    print "\t%s" % num

Die gewünschte Ausgabe wäre:

These numbers are in group a:
1
2
3
4
5
6
7
8
These numbers are in group b:
9
These numbers are in group c:
10
11
12
13

Wie kann ich dies tun, ohne Änderung big_gen () oder Drucker (), und vermeiden Sie die gesamte Gruppe im Speicher auf einmal zu speichern? (Im wirklichen Leben ist die Gruppen große )

War es hilfreich?

Lösung

Klar, das tut, was Sie wollen:

import itertools
import operator

def main():
  for let, gen in itertools.groupby(big_gen(), key=operator.itemgetter(0)):
    secgen = itertools.imap(operator.itemgetter(1), gen)
    printer(let, secgen)

groupby macht den Großteil der Arbeit hier - die key= es nur sagt, was Feld Gruppe.

Der resultierende Generator nur in einem imap gewickelt werden muss, weil Sie Ihre printer Unterschrift angegeben haben einen Iterator über Nummer zu nehmen, während von Natur groupby Iteratoren über die gleichen Elemente gibt es als seine Eingabe wird - hier, 2-Elemente Tupel mit einem Buchstaben und eine Zahl -. aber das ist nicht wirklich alles, was relevant für Ihre Frage Titel

Die Antwort auf diesen Titel ist, dass, ja, kann eine Python-Funktion sehr gut, den Job Sie wollen - itertools.groupby in der Tat tut genau das. Ich empfehle das Studium des itertools Modul vorsichtig, es ist ein sehr nützliches Werkzeug (und liefert großartige Leistung als gut).

Andere Tipps

Sie haben ein kleines Problem hier. Sie würden die Funktion Drucker () wie für jede Gruppe einen Generator zu nehmen, aber in Wirklichkeit haben Sie den gleichen Generator alle Gruppen ergibt. Sie haben zwei Möglichkeiten, wie ich es sehe:

1) Veränderung big_gen () Generatoren zu erhalten:

import random
def big_gen():
  i = 0
  group = 'a'
  while group != 'd':
    def gen():
        i += 1
        yield i
        if random.random() < 0.20:
            group = chr(ord(group) + 1)
    yield group, gen

 from itertools import imap
 imap(lambda a: printer(*a), big_gen())

2) Ändern der Drucker () zu halten Zustand und beachten, wenn die Gruppe (Beibehaltung Ihrer ursprünglichen big_gen () Funktion):

def printer(generator):
  group = None
  for grp, num in generator:
    if grp != group:
        print "These numbers are in group %s:" % grp
        group = grp
    print "\t%s" % num
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top