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

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
dll-live
User
Beiträge: 32
Registriert: Dienstag 11. August 2020, 09:25
Wohnort: CH

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
__deets__
User
Beiträge: 14533
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was ist denn an einer if-Abfrage unschick? Kannst du mal etwas weiter ausholen, was dein zu lösendes Problem ist?
christheturtle
User
Beiträge: 42
Registriert: Sonntag 29. September 2019, 12:36

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
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@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.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17746
Registriert: Sonntag 21. Oktober 2012, 17:20

@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
dll-live
User
Beiträge: 32
Registriert: Dienstag 11. August 2020, 09:25
Wohnort: CH

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
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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))
Benutzeravatar
DeaD_EyE
User
Beiträge: 1020
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

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/
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Sirius3
User
Beiträge: 17746
Registriert: Sonntag 21. Oktober 2012, 17:20

@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))
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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))
dll-live
User
Beiträge: 32
Registriert: Dienstag 11. August 2020, 09:25
Wohnort: CH

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
Sirius3
User
Beiträge: 17746
Registriert: Sonntag 21. Oktober 2012, 17:20

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)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Und dann gibt es noch das gute alte bisect-Modul.
Das Leben ist wie ein Tennisball.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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.
christheturtle
User
Beiträge: 42
Registriert: Sonntag 29. September 2019, 12:36

__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!
__deets__
User
Beiträge: 14533
Registriert: Mittwoch 14. Oktober 2015, 14:29

@christheturtle Bitte keinen Full Quote des Beitrags davor. Den kann man ja auch so schon lesen.
Antworten