Seite 1 von 1

Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Dienstag 11. August 2020, 09:34
von dll-live
Sehr geehrtes Forum.

Guten Morgen und anbei mein erster "Frage"-Beitrag.

Wie kann ich die Frage im Titel in Python elegant lösen?

Anbei ein Beisiel:

Wert (56):
>= 80 => Rückgabewert 1
>= 70 => Rückgabewert 2
....
(else => Rückgabewert n) <= die ist "nice to have"

Mit x-if Abfragen kann ich es lösen, ich hoffe das es schickere Varianten gibt.

Für euere Hilfe bedanke ich mich herzlich.
Freundliche Grüsse
Daniel

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Dienstag 11. August 2020, 10:47
von __deets__
Was ist denn an einer if-Abfrage unschick? Kannst du mal etwas weiter ausholen, was dein zu lösendes Problem ist?

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Dienstag 11. August 2020, 11:16
von christheturtle
Hallo,

ich denke auch, die if-Geschichte ist hier durchaus geeignet.

So zum Beispiel:

Code: Alles auswählen

def groesser_gleich(wert,vergleichswert):
	if wert >= vergleichswert:
		return True
	else: 
		return False 

Wenn du dann z.B.

Code: Alles auswählen

groesser_gleich(50,80)
eingibst, gibt dir die Funktion zurück, ob dein Wert (hier 50) größer/ gleich deinem Vergleichswert (hier 80) ist.

In der Hoffnung, deine Frage richtig verstanden zu haben... :)
Chris

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Dienstag 11. August 2020, 11:35
von __blackjack__
@christheturtle: Der Vergleich beim ``if`` wird ja bereits zu einem Wahrheitswert ausgewertet. *Den* kann man auch einfach als Ergebnis liefern:

Code: Alles auswählen

def groesser_gleich(wert, vergleichswert):
    return wert >= vergleichswert
Damit fängt die Funktion dann aber an wenig Sinn zu machen, weil man diesen Ausdruck jetzt nicht unbedingt in eine Funktion auslagern muss, denn eine Funktion `groesser_gleich()` zu haben ist eher nicht verständlicher oder kürzer als gleich die Operation an der Aufrufstelle zu verwenden.

Sollte man aus Gründen diesen Operator als Funktion benötigen, muss man sich das nicht selbst schreiben, denn alle Operatoren als Funktion gibt es bereits in der Standardbibliothek im `operator`-Modul:

Code: Alles auswählen

from operator import ge as groesser_gleich
@dll-live: Du könntest Grenzwerte und Ergebnis als Tupel zusammenfassen und in einer Liste stecken und eine Schleife über diese Paare schreiben, in der dann getestet und ggf. ”returned” wird.

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Dienstag 11. August 2020, 11:40
von Sirius3
@dll-live: so etwas muß man selbst programmieren, z.B. mit einem Wörterbuch

Code: Alles auswählen

TABLE = {
    80: "Rückgabewert 1",
    70: "Rückgabewert 2",
    50: "Rückgabewert 3",
}
DEFAULT = "nice to have"

def test(value):
    for boundary, return_value in sorted(TABLE.items(), reverse=True):
        if value >= boundary:
            return return_value
    return DEFAULT

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Dienstag 11. August 2020, 17:36
von dll-live
Hallo zusammen.

Besten Dank für die Antworten!
Nun der Reihe nach:
Warum nicht x-if Abfragen benutzen? => Weil es mir widerstrebt, und ich es schöner finde wenn alles an einem Ort (untereinander) definiert ist, so habe ich meiner Meinung nach auch mehr Übersicht.
Der Code Schnipsel von @Sirius3 ist das wonach ich gesucht habe. => Besten Dank!

Für was wird das Programm verwendet?
Mit Hilfe zweier Eingaben (Gewicht (in Kn), und maximale Bremskraft (ebenfalls Kn)) wird das Verhältnis berechnet, anschliessend über über diese (gesuchte Funktion) das Passendstes (vorhandene Verhältnis) rausgesucht und die weiteren Parameter eingestellt, damit Bremsversuche gemacht werden können.

Nochmals herzlichen Dank,an alle die sich an der Lösungsfindung beteiligt haben.

Freundliche Grüsse
Daniel

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Mittwoch 12. August 2020, 07:14
von snafu
Also suchst du eigentlich den nächstgelegenen Wert? Das kann man zB so machen:

Code: Alles auswählen

from operator import itemgetter

VALUES = [80, 70, 55, 40, 25, 15, 10, 5]

def find_best_value(x, values):
    deltas = [(i, abs(x - v)) for i, v in enumerate(values)]
    index, _ = min(deltas, key=itemgetter(1))
    return values[index]

print("Bester Wert:", find_best_value(42, VALUES))

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Mittwoch 12. August 2020, 13:54
von DeaD_EyE
Man kann es noch auf die Spitze treiben.
Wenn man z.B. ein Mapping mit Lücken hat, muss man ein oberes und unteres Limit definieren können.

Code: Alles auswählen

TABLE = {
    (0, 10): "Foo1",
    # hier ist eine Lücke
    (14, 20): "Foo2",
    # hier auch
    (22, 23): "Foo3",
    (23, 24): "Foo4",
}
DEFAULT = "Wert ist nicht im Bereich"


def bereich(wert):
    for (lower, upper), text in TABLE.items():
        if lower <= wert < upper:
            return text
    else:
        return DEFAULT
Oder man nimmt etwas Fertiges: https://pypi.org/project/rangedict/

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Mittwoch 12. August 2020, 16:18
von Sirius3
@snafu: warum speichert Du den Index in der Liste, wenn Du später sowieso den Wert möchtest?

Code: Alles auswählen

from operator import itemgetter

VALUES = [80, 70, 55, 40, 25, 15, 10, 5]

def find_best_value(x, values):
    deltas = [(v, abs(x - v)) for v in values]
    value, _ = min(deltas, key=itemgetter(1))
    return value

print("Bester Wert:", find_best_value(42, VALUES))
oder gleich als key-Funktion:

Code: Alles auswählen

def find_best_value(x, values):
    return min(values, key=lambda v: abs(x - v))

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Mittwoch 12. August 2020, 18:07
von snafu
Sirius3 hat geschrieben: Mittwoch 12. August 2020, 16:18

Code: Alles auswählen

def find_best_value(x, values):
    return min(values, key=lambda v: abs(x - v))
Sieht sehr gut aus. War doch klar, dass es auch als Einzeiler möglich ist. ;)

Hier die Variante mit Mindestwerten als Einzeiler. :)

Code: Alles auswählen

reduce(lambda a,b: a if a <= x < b else b, sorted(values))
Macht zwar ein paar unnötige Vergleiche, ist dafür aber schön kompakt. Für einen spürbaren Laufzeitunterschied bräuchte es da schon ziemlich viele Werte. Und bei den Deltas via min() hat man das Problem ja genau so.

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Mittwoch 12. August 2020, 21:15
von snafu
Es gab bei mir noch ein Problem, wenn x kleiner als der niedrigste Wert war. Dann wurde immer der höchste Wert als Ergebnis geliefert. Mit der folgenden Zeile ist dieses Verhalten geändert. Wenn hier x "zu klein" ist, wird der niedrigste Wert angenommen. Analog dazu der höchste, wenn x größer als alle anderen Werte ist.

Code: Alles auswählen

reduce(lambda a, b: a if x >= a else b, sorted(values, reverse=True))

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Donnerstag 13. August 2020, 09:01
von dll-live
Hallo Zusammen.

Besten Dank für die weiteren Antworten.
@snafu: Ich suche nicht einfach den nächst passenden Wert sondern den nächst tieferen passenden wert. (zb.: 80 bei 89 und nicht 90)
@DeaD_EyE: Besten Dank für dein Beispiel. Im Anwendungsfall gibt es keine Lücken. (Das ist zu 100% ausgeschlossen)

Freundliche Grüsse
Daniel

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Donnerstag 13. August 2020, 09:32
von Sirius3
Wenn Du den nächst kleineren Wert suchst, dann wäre das

Code: Alles auswählen

def find_best_value(x, values):
    return max(v for v in values if x>v)

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Donnerstag 13. August 2020, 14:02
von EyDu
Und dann gibt es noch das gute alte bisect-Modul.

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Donnerstag 13. August 2020, 15:19
von snafu
Um die Anregung mit bisect mal zu übernehmen:

Code: Alles auswählen

from bisect import bisect

def get_breakpoint(value, breakpoints):
    index = bisect(sorted(breakpoints), value)
    if not index:
        raise ValueError("Did not match any breakpoint")
    return breakpoints[index - 1]

breakpoints = [10, 15, 20, 30, 50, 70, 100]
for value in (11, 20, 29, 101, 4):
    print(get_breakpoint(value, breakpoints))
Wirklich schneller dürfte das aber nicht sein, solange die Breakpoints überschaubar bleiben. Kann man aber natürlich alles messen, wenn man möchte. Würde ich aber nur dann tun, wenn sich der Vorgang wirklich langsam anfühlt. Das bisect-Modul ist halt auch "nur" in reinem Python programmiert und an sich für andere Anwendungsfälle konzipiert.

PS: sorted() ist nur zur Sicherheit eingebaut. Wenn die Breakpoints schon sortiert vorliegen, wie bei dem Test, dann ist es unnötig. Die Implementierung für's Sortieren in Python bricht zum Glück schnell ab, wenn sie erkennt, dass bereits sortierte Werte vorliegen. Somit hält sich der Mehraufwand in Grenzen.

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Freitag 14. August 2020, 09:50
von christheturtle
__blackjack__ hat geschrieben: Dienstag 11. August 2020, 11:35 @christheturtle: Der Vergleich beim ``if`` wird ja bereits zu einem Wahrheitswert ausgewertet. *Den* kann man auch einfach als Ergebnis liefern:

Code: Alles auswählen

def groesser_gleich(wert, vergleichswert):
    return wert >= vergleichswert
Damit fängt die Funktion dann aber an wenig Sinn zu machen, weil man diesen Ausdruck jetzt nicht unbedingt in eine Funktion auslagern muss, denn eine Funktion `groesser_gleich()` zu haben ist eher nicht verständlicher oder kürzer als gleich die Operation an der Aufrufstelle zu verwenden.

Sollte man aus Gründen diesen Operator als Funktion benötigen, muss man sich das nicht selbst schreiben, denn alle Operatoren als Funktion gibt es bereits in der Standardbibliothek im `operator`-Modul:

Code: Alles auswählen

from operator import ge as groesser_gleich
@dll-live: Du könntest Grenzwerte und Ergebnis als Tupel zusammenfassen und in einer Liste stecken und eine Schleife über diese Paare schreiben, in der dann getestet und ggf. ”returned” wird.
Guter Hinweis, Danke!

Re: Prüfen ob ein Wert grösser oder gleich, vorgegebenen Werten ist und dann entsprechend eine Rückgabe erhalten?

Verfasst: Freitag 14. August 2020, 10:09
von __deets__
@christheturtle Bitte keinen Full Quote des Beitrags davor. Den kann man ja auch so schon lesen.