Seite 1 von 1
Miniumum einer Liste ermitteln + Bedingung
Verfasst: Montag 8. September 2008, 19:58
von Daniel_SGe
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:
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
Verfasst: Montag 8. September 2008, 20:04
von 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.
Verfasst: Montag 8. September 2008, 20:15
von Daniel_SGe

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.
Verfasst: Montag 8. September 2008, 20:16
von Leonidas
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)
Re: Miniumum einer Liste ermitteln + Bedingung
Verfasst: Montag 8. September 2008, 20:24
von numerix
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
Verfasst: Montag 8. September 2008, 20:33
von Daniel_SGe
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.
Verfasst: Montag 8. September 2008, 20:46
von 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
Verfasst: Montag 8. September 2008, 22:00
von numerix
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
Verfasst: Dienstag 9. September 2008, 13:18
von HWK
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
Verfasst: Dienstag 9. September 2008, 15:13
von Daniel_SGe
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]
Verfasst: Dienstag 9. September 2008, 17:35
von HWK
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
Verfasst: Dienstag 9. September 2008, 17:47
von 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
Verfasst: Dienstag 9. September 2008, 18:16
von Daniel_SGe
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?
Verfasst: Dienstag 9. September 2008, 19:44
von HWK
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
Verfasst: Dienstag 9. September 2008, 20:03
von 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.
Verfasst: Dienstag 9. September 2008, 20:38
von HWK
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
Verfasst: Mittwoch 10. September 2008, 21:28
von Daniel_SGe
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;)
Verfasst: Donnerstag 11. September 2008, 16:56
von HWK
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
Verfasst: Freitag 12. September 2008, 19:23
von Daniel_SGe
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:
wird zu:
Verfasst: Freitag 12. September 2008, 19:43
von 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.