Miniumum einer Liste ermitteln + Bedingung

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.
Daniel_SGe
User
Beiträge: 28
Registriert: Montag 8. September 2008, 19:39

Miniumum einer Liste ermitteln + Bedingung

Beitragvon Daniel_SGe » Montag 8. September 2008, 19:58

Hallo!

Folgendes Problem: Ich möchte von einer Liste Zeit, die in weitere Listen unterteilt ist (alles absolute Zahlenwerte), den Index der Subliste ermitteln für die gilt, dass diese den kleinsten Wert größer einer definierten Variable hat.

Bis jetzt sieht es so aus:

Code: Alles auswählen

print zeit.index(min(zeit))

Ich hab jetzt keine Ahnung wie ich dieses Minimum an die Bedingung : min>counter knüpfen kann.

Ich hoff mal ihr könnt mri helfen;)

LG

Daniel
BlackJack

Beitragvon BlackJack » Montag 8. September 2008, 20:04

Also mich hast Du gerade gründlich verwirrt.

Du hast eine Liste von Listen und möchtest den Index einer dieser Unterlisten haben für die *welche* Bedingung gilt?

Gib mal bitte Beispieldaten und was da warum als Ergebnis heraus kommen soll.
Daniel_SGe
User
Beiträge: 28
Registriert: Montag 8. September 2008, 19:39

Beitragvon Daniel_SGe » Montag 8. September 2008, 20:15

:D sry, wollt mich nur kurz halten...

Liste[A, B, C,...] wobei A, B usw. auch Listen sind.

Nun möchte ich einfach den Index (0,1,2,...) derjenigen Liste A,B,C usw. finden, für die folgendes gilt: Diese Liste beinhaltet das absolute Minimum aus allen Listen, wobei die Zahl mindestens der Variablen "counter" entsprechen soll.

Beispiel: Als Minimum in B stellt sich 60 heraus. Ich hätte den Index 1. counter ist allerdings 80, also brauch ich das nächstgrößere Minimum. Dieses befindet sich zufälligerweise in C, z.B. 100 und Index 2; letzteres sollte dann ausgegeben werden.
Benutzeravatar
Leonidas
Administrator
Beiträge: 16023
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Beitragvon Leonidas » Montag 8. September 2008, 20:16

Irgendwie sowas?

Code: Alles auswählen

counter = 3
zeitlisten = [[1, 2], [3, 4], [5, 6]]
current_min = None
current_min_list = None
for index, zeitchunk in enumerate(zeitlisten):
   for item in zeitchunk:
       if (current_min is None or item < current_min) and item > counter:
           current_min = item
           current_min_list = index

(ungetestet)
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Re: Miniumum einer Liste ermitteln + Bedingung

Beitragvon numerix » Montag 8. September 2008, 20:24

Daniel_SGe hat geschrieben:Ich hab jetzt keine Ahnung wie ich dieses Minimum an die Bedingung : min>counter knüpfen kann.


Dieses Teilproblem kannst du z.B. so lösen:

Code: Alles auswählen

>>> werte = [40,50,30,90,120]
>>> grenze = 70
>>> min(werte,key=lambda x:x<grenze)
90
Daniel_SGe
User
Beiträge: 28
Registriert: Montag 8. September 2008, 19:39

Beitragvon Daniel_SGe » Montag 8. September 2008, 20:33

hi!

danke für die schnelle antworten;)

@Leonidas: sieht ziemlich kompliziert aus... Werd mich erst dran wagen, wenn ich mit numerix augenscheinlich einfacheren vorschlag nich weiterkomm;)

@numerix: könntest du mir vll. die Funktionsweise des letzten Abschnitts erklären, damit ich weiß, inwiefern ich dies anpassen kann? Ich habs grad mal eingestezt und so richtig funktionierts noch nich...

//Edit:

Scheint an der Verkettung der Listen zu liegen. Ich erhalte als Wert generell 300. Das ist das Minimum der 1. Liste.
BlackJack

Beitragvon BlackJack » Montag 8. September 2008, 20:46

Code: Alles auswählen

from itertools import ifilter

def main():
    counter = 3
    zeit = [[1, 2], [3, 4], [5, 6]]
    dummy, i = min(ifilter(lambda t: t[0] >= counter,
                           ((min(xs), i) for i, xs in enumerate(zeit))))
    print i
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Beitragvon numerix » Montag 8. September 2008, 22:00

Oder so:

Code: Alles auswählen

zeiten = [[40,70,80], [50,90,70], [80,90,100], [30,80,20]]
counter = 85
mins = map(lambda v:(min(v,key=lambda x:x<=counter)>counter)*min(v,key=lambda x:x<=counter), zeiten)
try:
    print mins.index(min(mins) or min(mins,key=lambda x:x<=counter) or mins)
except ValueError:
    print "Kein Zeiten > %i" %counter
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Beitragvon HWK » Dienstag 9. September 2008, 13:18

Oder BlackJacks Lösung etwas abgewandelt, um komplett bei Generatoren zu bleiben:

Code: Alles auswählen

def main():
    counter = 3
    zeit = [[1, 2], [3, 4], [5, 6]]
    dummy, i = min(t for t in ((min(xs), i) for i, xs in enumerate(zeit))
                   if t[0] >= counter)
    print i
MfG
HWK
Daniel_SGe
User
Beiträge: 28
Registriert: Montag 8. September 2008, 19:39

Beitragvon Daniel_SGe » Dienstag 9. September 2008, 15:13

hi HWK!

Dein Vorschlag scheint zu funktionieren... Ich bin mir trotzdem nicht ganz der Funktionsweise bewusst... Der äußerste Teil berechnet ja im Prinzip min(min(x)),. das ist klar... wieso brauche ich jedoch die wertepaare xs und i? bzw. was bewirken diese überhaupt. (dummy müsste in dem Fall ja xs sein, wenn ixh das richtig sehe?) .

Weiterhin, wird ja im inneren Teil , wenn ich das so richtig interpretiere folgendes getan:
Für jedes t dieses inneren Minimums werden alle Indexe eines Wertepaars i,xs , für das counter>= 0 gilt gebildet. ?!

//EDIT:

Da scheint auch ein Fehler drin zu sein. Der algorithmus kann sich nur auf das 1. Element einer Liste beziehen, also auf das Minimum. Wenn ich jetzt deine Beispielliste nehmen würde, würde er für counter=6 nicht die Liste [5,6] nehmen sondern [7,8]
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Beitragvon HWK » Dienstag 9. September 2008, 17:35

xs braucht man zum Sortieren, i ist der Index, den man ja wissen will.
Der erste Generator (t for t in...) besteht nur aus Minima mit xs >= counter. Davon wird das kleinste bestimmt.
Zu Deinem Edit: Ich war mir da auch unsicher. Ich wollte erst BlackJack daraufhinweisen, dass sein Vorschlag nicht funktioniert. Ich habe mir dann aber noch mal Deine Spezifikation durchgelesen. Danach suchst Du ja das mindestens counter-große Minimum der Minimas. Scheinbar willst Du aber doch etwas anderes, was ich primär auch vermutet habe, nämlich: Den kleinsten Wert aus allen Listen, der mindestens gleich counter ist. Stimmt das?
MfG
HWK
BlackJack

Beitragvon BlackJack » Dienstag 9. September 2008, 17:47

Das funktioniert so wie Du's beschrieben hast, allerdings gibt's bei ``counter = 6`` das Problem, dass gar keine Liste mehr auf die Bedingungen zutrifft.

Nehmen wir's doch mal Schritt für Schritt auseinander. Vorbereitung:

Code: Alles auswählen

In [313]: counter = 3

In [314]: zeit = [[1, 2], [3, 4], [5, 6]]


Du willst den Index wissen, also numerieren wir die Listen mal durch und bilden Tupel der Form (index, (unter)liste):

Code: Alles auswählen

In [315]: list(enumerate(zeit))
Out[315]: [(0, [1, 2]), (1, [3, 4]), (2, [5, 6])]


Von den einzelnen Listen interessiert nur das Minimum, also bestimmen wir das. Und ausserdem wird die Reihenfolge in den neuen Tupeln umgekehrt, dass heisst wir haben jetzt (lokales_minimum, index):

Code: Alles auswählen

In [316]: list((min(xs), i) for i, xs in enumerate(zeit))
Out[316]: [(1, 0), (3, 1), (5, 2)]


Von diesem Zwischenergebnis müssen wir nun alle Tupel verwerfen, deren erstes Element kleiner als `counter` ist:

Code: Alles auswählen

In [317]: list(t for t in ((min(xs), i) for i, xs in enumerate(zeit)) if t[0] >= counter)
Out[317]: [(3, 1), (5, 2)]


Und davon suchen wir nun das Miminum, also noch einmal `min()` drum herum, und schon haben wir das gewünschte Ergebnis.

Code: Alles auswählen

In [318]: min(t for t in ((min(xs), i) for i, xs in enumerate(zeit)) if t[0] >= counter)
Out[318]: (3, 1)


`dummy` ist das Miminum der Liste am Index `i`. Falls Du den Wert im weiteren Verlauf noch benötigst, solltest Du natürlich einen passenden Namen verwenden.

Falls keine der Listen die Bedingungen erfüllt, weil `counter` zu gross ist, gibt's eine Ausnahme:

Code: Alles auswählen

In [319]: counter = 6

In [320]: min(t for t in ((min(xs), i) for i, xs in enumerate(zeit)) if t[0] >= counter)
---------------------------------------------------------------------------
<type 'exceptions.ValueError'>            Traceback (most recent call last)

/home/bj/<ipython console> in <module>()

<type 'exceptions.ValueError'>: min() arg is an empty sequence
Daniel_SGe
User
Beiträge: 28
Registriert: Montag 8. September 2008, 19:39

Beitragvon Daniel_SGe » Dienstag 9. September 2008, 18:16

Ich war mir da auch unsicher. Ich wollte erst BlackJack daraufhinweisen, dass sein Vorschlag nicht funktioniert. Ich habe mir dann aber noch mal Deine Spezifikation durchgelesen. Danach suchst Du ja das mindestens counter-große Minimum der Minimas. Scheinbar willst Du aber doch etwas anderes, was ich primär auch vermutet habe, nämlich: Den kleinsten Wert aus allen Listen, der mindestens gleich counter ist. Stimmt das?


Sry, wenn ich mich vll. etwas ungeschickt ausgedrückt hatte. Ich meinte definitiv letzteres. Verwirrend könnte gewesen sein, dass ich bei meinen eigenen ersten Versuchen bei min(liste) die kleinste liste herausbekommen hatte, und daher dachte , ich bräuchte davon wieder das Minimum.

Wie HWK schon sagte, suche ich also den kleinsten Wert aus allen Listen, der mindestens gleich counter ist, und den Index der Liste, in der sich dieser Wert befindet.

Nun zu BlackJack:

Erstmal danke für deine Bemühungen:)

Soweit ist mir das jetzt auch klar geworden. Was ich aber nich versteh ist der letzte Teil nach den gestrichelten Linien...

Wenn ich jetzt also noch die Bedingung wie oben genannt anpasse, müsste eigentlich das "innere" Minimum verschwinden, oder?
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Beitragvon HWK » Dienstag 9. September 2008, 19:44

Dann dürfte das die gewünschte Lösung liefern:

Code: Alles auswählen

def main():
    counter = 5
    zeit = [[1, 2], [3, 4], [5, 6], [7, 8]]
    dummy, i = min((min(xs), i)
                   for i, xs in enumerate([x for x in xs_ if x >= counter]
                                          for xs_ in zeit) if xs)
    print i
Geht aber sicher eleganter. Nicht funktional wäre es wohl auch verständlicher.
MfG
HWK
BlackJack

Beitragvon BlackJack » Dienstag 9. September 2008, 20:03

Hm okay, nächster Versuch:

Code: Alles auswählen

def f(counter, zeit):
    for i, xs in enumerate(zeit):
        try:
            yield (min(x for x in xs if x >= counter), i)
        except ValueError:
            pass

def main():
    counter = 3
    zeit = [[1, 2], [3, 4], [5, 6]]
    dummy, i = min(f(counter, zeit))
    print i


`f` müsste man wohl irgend einen passenderen Namen geben, `x` und `xs` eventuell auch. Aber ich hoffe das Ergebnis stimmt jetzt.

Das mit der "gestrichelten Linie": Heisst das Du weisst nicht wie man mit Ausnahmen umgeht, oder nur nicht warum die kommt? Diese hatte die Ursache das `min()` ein leeres "iterable" bekommen hat. Das Minimum von "Nichts" ist eben undefiniert. Das passiert auch immer noch falls `counter` grösser als alle Elemente in sämtlichen Unterlisten ist.

Wer ist online?

Mitglieder in diesem Forum: Bing [Bot]