Seite 1 von 1

Die ersten x Elemente eines Generators abrufen. Geht das?

Verfasst: Dienstag 19. Oktober 2010, 08:29
von mutetella
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?

Re: Die ersten x Elemente eines Generators abrufen. Geht das

Verfasst: Dienstag 19. Oktober 2010, 08:37
von Xynon1
mir fällt spontan nur

Code: Alles auswählen

list(generator)[:5]
ein.

Zerstört natürlich die Vorteile des generators.

Re: Die ersten x Elemente eines Generators abrufen. Geht das

Verfasst: Dienstag 19. Oktober 2010, 08:42
von mutetella
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.

Re: Die ersten x Elemente eines Generators abrufen. Geht das

Verfasst: Dienstag 19. Oktober 2010, 08:47
von Xynon1
richtig, danke für den Hinweis, hatte ich übersehen.

Re: Die ersten x Elemente eines Generators abrufen. Geht das

Verfasst: Dienstag 19. Oktober 2010, 08:55
von BlackJack
Aber man kann daraus trotzdem etwas verwenden: ``list(islice(generator, 5))``

Re: Die ersten x Elemente eines Generators abrufen. Geht das

Verfasst: Dienstag 19. Oktober 2010, 08:55
von cofi
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.

Re: Die ersten x Elemente eines Generators abrufen. Geht das

Verfasst: Dienstag 19. Oktober 2010, 09:20
von mutetella
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)

Re: Die ersten x Elemente eines Generators abrufen. Geht das

Verfasst: Dienstag 19. Oktober 2010, 09:30
von cofi
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.

Re: Die ersten x Elemente eines Generators abrufen. Geht das

Verfasst: Dienstag 19. Oktober 2010, 10:16
von mutetella
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.

Re: Die ersten x Elemente eines Generators abrufen. Geht das

Verfasst: Dienstag 19. Oktober 2010, 10:49
von cofi

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 ;)