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

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

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

: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.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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 (former) Modvoice
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

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

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

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

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

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

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

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

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

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

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

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.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Hier eine ganz primitive Variante, aber vom Laufzeitverhalten vielleicht noch schneller:

Code: Alles auswählen

def f(lists, lim):
    ind = val = None
    for i, list_ in enumerate(lists):
        for item in list_:
            if item >= lim and (val is None or item < val):
                ind, val = i, item
    return (ind, val)

print f([[1, 2], [3, 4], [5, 6, 10], [7, 8]], 9)
MfG
HWK
Daniel_SGe
User
Beiträge: 28
Registriert: Montag 8. September 2008, 19:39

Hi, ich arbeite mich zur zeit durch den letzten vorschlag von blackjack... Falls es eventuell anders benötigt wird, schau ich mir auch deinen Vorschlag an HWK:) ... Laufzeitverhalten ist aber nicht unbedingt höchste Priorität... Is nur mittlere Spielerei;)

Vorschlag von BlackJack scheint endlich zu funktionieren, oder ich hab eben den Fehler noch nciht gefunden^^


Was ich aber immer noch nciht ganz verstehe ist diese Ausnahme mit dem Valueerror. Bzw. ich weiß schon, was es bewirken soll, nur nicht wie ich es weiterverarbeite;)
der letzte teil dummy, i =min(...) gibt mir nämlich schließlich wegen eines leeren arguments eine Fehlermeldung aus.... (ich hab den ganzen vorgang in eine while-Schleife eingebunden). Ich hätte aber gerne, dass die while-Schleife im Prinzip bei einem solchen "ValueError" abbricht, bzw. dass min(...) einen bestimmten Wert annimmt, den ich weiterverarbeiten könnte;)
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Deshalb vielleicht doch die nicht so funktionale Variante. Dort ist das einfacher zu regeln und dürfte auch verständlicher sein. Schau dir's mal an.
MfG
HWK
Daniel_SGe
User
Beiträge: 28
Registriert: Montag 8. September 2008, 19:39

Hi!

Hab jetzt noch ein bischen an dem vorherigen Vorschlag von BlackJack rumprobiert... Scheint jetzt zu funktionieren...

Was mri jetzt noch fehlt ist ein kleine Funktion, mit der ich eine Datei mit verschiedenen Argumenten (manchmal auch mehrere pro Zeile) in Tupel umwandeln kann... (soll cih dafür einen neuen Thread aufmachen?) ... Bis jetzt sieht das bei mir so aus:

Code: Alles auswählen

datei = raw_input('''Falls gewünscht: Pfad der Versuchsliste...
''')
daten = open(datei, "r") 
dateien = splitfields(daten)
Es scheitert im Moment allerdings daran, dass mir splitfields mit NameError: name 'splitfields' is not defined
quittiert wird.

Was ich erreichen möchte: Jede Zeile wird in ein Tupel umgewandelt in denen jedes "Wort" einer Zeile jeweils als Element des Tupels umgewandelt wird.

Beispiel:

Code: Alles auswählen

a b c
d e
wird zu:

Code: Alles auswählen

((a, b, c), (d, e))
BlackJack

Neuer Thread für ein neues Problem wäre nicht schlecht.

Müssen es unbedingt Tupel sein?

Code: Alles auswählen

In [431]: f = open('test.txt')

In [432]: [line.split() for line in f]
Out[432]: [['a', 'b', 'c'], ['d', 'e']]

In [433]: f.close()
Hier kommen wir aber so langsam bei ziemlich grundlegenden Operationen an.
Antworten