Die ersten x Elemente eines Generators abrufen. Geht das?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Hallo,

gibt es für

Code: Alles auswählen

generator[0:5] #was natürlich nicht gehen kann
außer

Code: Alles auswählen

[element for element in islice(generator, 5)]
noch andere Möglichkeiten, die ersten Elemente eines Generators abzurufen. Vielleicht eine Built-in Funktion, die ich nicht kenne...

Oder ist islice() für sowas ok?
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

mir fällt spontan nur

Code: Alles auswählen

list(generator)[:5]
ein.

Zerstört natürlich die Vorteile des generators.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

Xynon1 hat geschrieben:Zerstört natürlich die Vorteile des generators.
Und ist auf einen "unendlichen" Generator nicht anwendbar, da hierbei ja erstmal alle Elemente des Generators durchlaufen werden.
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

richtig, danke für den Hinweis, hatte ich übersehen.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

Aber man kann daraus trotzdem etwas verwenden: ``list(islice(generator, 5))``
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Nuja, du kannst auch direkt mit `islice` auf den Generator zugreifen oder benoetigst du unbedingt die Liste? Daneben koenntest du einfach ueber `enumerate(generator)` iterieren und bei 5 abbrechen.

Viele Moeglichkeiten. Wenn du vielleicht noch was zum Kontext sagst kann man dir bestimmt konkreter helfen.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

cofi hat geschrieben:Wenn du vielleicht noch was zum Kontext sagst kann man dir bestimmt konkreter helfen.
Es geht darum, Wiederholungen eines Termins zu begrenzen, z. B. 'Diesen Termin alle 2 Tage bis zum 14. Dezember 2010 wiederholen.' Soweit kein Problem, das end_date ist hier ja bereits bekannt. Sofern allerdings nur bekannt ist, dass die 2tägige Wiederholung 5 x stattfinden soll, braucht es eine Methode, das end_date zu ermitteln.
Ich habe dafür eine Methode 'recurrence_list()' gebastelt, die mir eine bestimmte Anzahl von passenden Wiederholungen zurückgibt. In diesem Fall bedeutet passend, dass die date's, ausgehend vom start_date jeweils 2 Tage auseinanderliegen, nicht in exceptions enthalten sind und sich innerhalb start_date und end_date (das, wenn noch nicht bekannt, datetime.date(9999, 12, 31) ist) befinden.

Code: Alles auswählen

from datetime import date as Date, timedelta as TimeDelta
from itertools import ifilter, islice

MAX_DATE = Date.max

class Recurrence(object):
    def __init__(self, start_date, end_date=MAX_DATE, \
            count=None, exceptions=[]):
        self.start_date = start_date
        self.end_date = end_date
        self.count = count
        self.exceptions = set(exceptions)
        if count is not None:
            self.end_date = self.recurrence_list(count)[-1]

    def recurrence_list(self, count, date=None,):
        if date is None:
            date = self.start_date
        count = count * self.recurrence_len
        return [elements for elements in islice(self._iter_check(), count)]

    def _basic_check(self, date):
        return self._exceptions_check(date) \
            and self._range_check(date)

    def _exceptions_check(self, date):
        return date not in self.exceptions

    def _range_check(self, date):
        return self.start_date < date <= self.end_date

    def _iter_check(self, start_date=None, end_date=None):
        if start_date is None:
            start_date = self.start_date
        if end_date is None:
            end_date = self.end_date
        return ifilter(self.check, iter_dates(self.start_date, 
            self.end_date))


class DailyRecurrence(Recurrence):
    def __init__(self, start_date, interval, \
            end_date=MAX_DATE, count=None, exceptions=[]):
        self.interval = interval
        self.recurrence_len = 1
        Recurrence.__init__(self, start_date, end_date, count, exceptions)

    def check(self, date):
        return self._basic_check(date) \
            and self._check_interval(date)

    def _check_interval(self, date):
        day_distance = (date - self.start_date).days
        return day_distance % self.interval == 0

def iter_dates(start_date, end_date):
    next = TimeDelta(days=1)
    while start_date <= end_date:
        yield start_date
        start_date += next
Der Aufruf sieht dann so aus:

Code: Alles auswählen

In [239]: d = calendar.DailyRecurrence(datetime.date(2010,10,1), 2, count=5)

In [240]: d.end_date
Out[240]: datetime.date(2010, 10, 11)
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

In dem Fall brauchst du dann die Liste - sofern du den Aufruf nicht aenderst, haette da jetzt aber auch keine sinnvolle Idee -, allerdings wuerde ich da BlackJacks Vorschlag vorziehen.

Anstatt den `_*_check` wuerde ich Namen der Art `_is_*` bzw `_in_*` vorschlagen, dann sieht man auch gleich den Sinn des Tests.
mutetella
User
Beiträge: 1695
Registriert: Donnerstag 5. März 2009, 17:10
Kontaktdaten:

cofi hat geschrieben:...allerdings wuerde ich da BlackJacks Vorschlag vorziehen.
Warum?
cofi hat geschrieben:Anstatt den `_*_check` wuerde ich Namen der Art `_is_*` bzw `_in_*` vorschlagen, ...
Ok, macht Sinn, werd' ich ändern.
Entspanne dich und wisse, dass es Zeit für alles gibt. (YogiTea Teebeutel Weisheit ;-) )
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Code: Alles auswählen

[elements for elements in islice(self._iter_check(), count)]
finde ich gegenueber

Code: Alles auswählen

list(islice(self._iter_check(), count)
zu schwalig, v.a. geht die Itention da etwas unter. Wenn du doch daran festhaelst, wuerde ich aber `elements` zu `element` machen ;)
Antworten