Gibt es eine kompaktere oder pythonischere Möglichkeit, den booleschen Ausdruck zu schreiben?
a + b == c or a + c == b or b + c == a
Ich hatte die Idee dass
a + b + c in (2*a, 2*b, 2*c)
aber das ist ein bisschen seltsam.
Gibt es eine kompaktere oder pythonischere Möglichkeit, den booleschen Ausdruck zu schreiben?
a + b == c or a + c == b or b + c == a
Ich hatte die Idee dass
a + b + c in (2*a, 2*b, 2*c)
aber das ist ein bisschen seltsam.
Antworten:
Wenn wir uns das Zen von Python ansehen, betonen Sie meine:
Das Zen von Python, von Tim Peters
Schön ist besser als hässlich.
Explizit ist besser als implizit.
Einfach ist besser als komplex.
Komplex ist besser als kompliziert.
Wohnung ist besser als verschachtelt.
Spärlich ist besser als dicht.
Lesbarkeit zählt.
Sonderfälle sind nicht speziell genug, um gegen die Regeln zu verstoßen.
Obwohl Praktikabilität die Reinheit übertrifft.
Fehler sollten niemals stillschweigend vergehen.
Sofern nicht ausdrücklich zum Schweigen gebracht.
Verweigern Sie angesichts von Zweideutigkeiten die Versuchung zu raten.
Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun.
Obwohl dieser Weg zunächst vielleicht nicht offensichtlich ist, es sei denn, Sie sind Niederländer.
Jetzt ist besser als nie.
Obwohl nie oft besser ist alsgerade jetzt.
Wenn die Implementierung schwer zu erklären ist, ist es eine schlechte Idee.
Wenn die Implementierung leicht zu erklären ist, ist dies möglicherweise eine gute Idee.
Namespaces sind eine großartige Idee - lasst uns mehr davon machen!
Die pythonischste Lösung ist die, die am klarsten, einfachsten und am einfachsten zu erklären ist:
a + b == c or a + c == b or b + c == a
Noch besser ist, dass Sie Python nicht einmal kennen müssen, um diesen Code zu verstehen! Es ist das einfach. Dies ist vorbehaltlos die beste Lösung. Alles andere ist intellektuelle Masturbation.
Darüber hinaus ist dies wahrscheinlich auch die Lösung mit der besten Leistung, da es der einzige von allen Vorschlägen ist, der einen Kurzschluss verursacht. Wenn a + b == c
nur eine einzige Addition und ein Vergleich durchgeführt werden.
Lösen der drei Gleichungen für a:
a in (b+c, b-c, c-b)
Python hat eine any
Funktion, die or
alle Elemente einer Sequenz ausführt. Hier habe ich Ihre Aussage in ein 3-Element-Tupel umgewandelt.
any((a + b == c, a + c == b, b + c == a))
Beachten Sie, dass dies ein or
Kurzschluss ist. Wenn die Berechnung der einzelnen Bedingungen teuer ist, ist es möglicherweise besser, das ursprüngliche Konstrukt beizubehalten.
any()
und all()
Kurzschluss auch.
any
überhaupt ausgeführt wird.
any
und all
"Kurzschluss" des Prozesses der Prüfung der Iterierbarkeit, die sie erhalten; Wenn es sich bei dieser Iterierbarkeit jedoch eher um eine Sequenz als um einen Generator handelt, wurde sie bereits vollständig ausgewertet, bevor der Funktionsaufruf erfolgt .
any
, Single-indent des ):
in der if
Erklärung), die viel zur besseren Lesbarkeit hilft , bei der Mathematik beteiligt ist
Wenn Sie wissen, dass Sie nur mit positiven Zahlen zu tun haben, funktioniert dies und ist ziemlich sauber:
a, b, c = sorted((a, b, c))
if a + b == c:
do_stuff()
Wie gesagt, das funktioniert nur bei positiven Zahlen; Aber wenn Sie wissen, dass sie positiv sein werden, ist dies eine sehr lesbare Lösung, IMO, sogar direkt im Code im Gegensatz zu einer Funktion.
Sie könnten dies tun, was einige wiederholte Berechnungen durchführen könnte; Sie haben jedoch keine Leistung als Ziel angegeben:
from itertools import permutations
if any(x + y == z for x, y, z in permutations((a, b, c), 3)):
do_stuff()
Oder ohne permutations()
und die Möglichkeit wiederholter Berechnungen:
if any(x + y == z for x, y, z in [(a, b, c), (a, c, b), (b, c, a)]:
do_stuff()
Ich würde diese oder eine andere Lösung wahrscheinlich in eine Funktion einfügen. Dann können Sie die Funktion in Ihrem Code einfach sauber aufrufen.
Persönlich würde ich nur die erste Methode in Ihrer Frage verwenden, es sei denn, ich benötige mehr Flexibilität für den Code. Es ist einfach und effizient. Ich könnte es immer noch in eine Funktion setzen:
def two_add_to_third(a, b, c):
return a + b == c or a + c == b or b + c == a
if two_add_to_third(a, b, c):
do_stuff()
Das ist ziemlich pythonisch und wahrscheinlich der effizienteste Weg, dies zu tun (der zusätzliche Funktionsaufruf beiseite); Sie sollten sich jedoch sowieso nicht zu viele Sorgen um die Leistung machen, es sei denn, dies verursacht tatsächlich ein Problem.
Wenn Sie nur drei Variablen verwenden, dann Ihre ursprüngliche Methode:
a + b == c or a + c == b or b + c == a
Ist schon sehr pythonisch.
Wenn Sie vorhaben, mehr Variablen zu verwenden, können Sie folgendermaßen argumentieren:
a + b + c in (2*a, 2*b, 2*c)
Ist sehr klug, aber lassen Sie uns darüber nachdenken, warum. Warum funktioniert das?
Nun, durch eine einfache Arithmetik sehen wir Folgendes:
a + b = c
c = c
a + b + c == c + c == 2*c
a + b + c == 2*c
Und dies muss entweder für a, b oder c gelten, was bedeutet, dass es ja gleich 2*a
ist 2*b
, oder 2*c
. Dies gilt für eine beliebige Anzahl von Variablen.
Eine gute Möglichkeit, dies schnell zu schreiben, besteht darin, einfach eine Liste Ihrer Variablen zu erstellen und deren Summe mit einer Liste der doppelten Werte zu vergleichen.
values = [a,b,c,d,e,...]
any(sum(values) in [2*x for x in values])
Um der Gleichung weitere Variablen hinzuzufügen, müssen Sie lediglich Ihre Werteliste mit 'n' neuen Variablen bearbeiten und nicht 'n' Gleichungen schreiben
a=-1
, b=-1
, c=-2
, dann a+b=c
aber a+b+c = -4
und 2*max(a,b,c)
ist-2
abs()
Aufrufen ist es Pythonic als das OP-Snippet (ich würde es tatsächlich als deutlich weniger lesbar bezeichnen).
any(sum(values) == 2*x for x in values)
müssten Sie nicht das ganze Verdoppeln im Voraus durchführen, genauso wie nötig.
Der folgende Code kann verwendet werden, um jedes Element iterativ mit der Summe der anderen zu vergleichen, die aus der Summe der gesamten Liste ohne dieses Element berechnet wird.
l = [a,b,c]
any(sum(l)-e == e for e in l)
[]
Klammern aus der zweiten Zeile entfernen , wird dies sogar wie das Original mit or
...
any(a + b + c == 2*x for x in [a, b, c])
ziemlich nah an dem Vorschlag des OP
Versuchen Sie nicht, es zu vereinfachen. Stattdessen nennen , was Sie mit einer Funktion tun:
def any_two_sum_to_third(a, b, c):
return a + b == c or a + c == b or b + c == a
if any_two_sum_to_third(foo, bar, baz):
...
Wenn Sie die Bedingung durch etwas "Kluges" ersetzen, wird sie möglicherweise kürzer, aber nicht lesbarer. Es zu belassen, wie es ist, ist jedoch auch nicht sehr lesbar, da es schwierig ist zu wissen, warum Sie diese drei Bedingungen auf einen Blick überprüfen. Dies macht absolut klar, wonach Sie suchen.
In Bezug auf die Leistung erhöht dieser Ansatz zwar den Overhead eines Funktionsaufrufs, beeinträchtigt jedoch niemals die Lesbarkeit für die Leistung, es sei denn, Sie haben einen Engpass gefunden, den Sie unbedingt beheben müssen. Und messen Sie immer, da einige clevere Implementierungen unter bestimmten Umständen einige Funktionsaufrufe optimieren und einbinden können.
Python 3:
(a+b+c)/2 in (a,b,c)
(a+b+c+d)/2 in (a,b,c,d)
...
Es lässt sich auf eine beliebige Anzahl von Variablen skalieren:
arr = [a,b,c,d,...]
sum(arr)/2 in arr
Im Allgemeinen stimme ich jedoch zu, dass die Originalversion besser lesbar ist, wenn Sie nicht mehr als drei Variablen haben.
[x for x in range(pow(2,30)) if x != ((x * 2)/ pow(2,1))]
(a+b-c)*(a+c-b)*(b+c-a) == 0
Wenn die Summe von zwei beliebigen Begriffen gleich dem dritten Begriff ist, ist einer der Faktoren Null, wodurch das gesamte Produkt Null wird.
(a+b<>c) && (a+c<>b) && (b+c<>a) == false
Wie wäre es einfach:
a == b + c or abs(a) == abs(b - c)
Beachten Sie, dass dies nicht funktioniert, wenn Variablen ohne Vorzeichen sind.
Unter dem Gesichtspunkt der Codeoptimierung (zumindest auf der x86-Plattform) scheint dies die effizienteste Lösung zu sein.
Moderne Compiler integrieren beide abs () - Funktionsaufrufe und vermeiden Vorzeichentests und nachfolgende bedingte Verzweigungen, indem sie eine clevere Folge von CDQ-, XOR- und SUB-Anweisungen verwenden . Der obige High-Level-Code wird daher nur mit ALU-Befehlen mit geringer Latenz, hohem Durchsatz und nur zwei Bedingungen dargestellt.
fabs()
kann für float
Typen verwendet werden;).
Die von Alex Varga "a in (b + c, bc, cb)" bereitgestellte Lösung ist kompakt und mathematisch schön, aber ich würde Code nicht so schreiben, weil der nächste Entwickler den Zweck des Codes nicht sofort verstehen würde .
Mark Ransoms Lösung von
any((a + b == c, a + c == b, b + c == a))
ist klarer, aber nicht viel prägnanter als
a + b == c or a + c == b or b + c == a
Wenn ich Code schreibe, den jemand anderes anschauen muss oder den ich lange später anschauen muss, wenn ich vergessen habe, was ich beim Schreiben gedacht habe, kann es mehr schaden als nützen, zu kurz oder klug zu sein. Code sollte lesbar sein. So prägnant ist gut, aber nicht so prägnant, dass der nächste Programmierer es nicht verstehen kann.
Die Anfrage ist kompakter ODER pythonischer - ich habe mich an kompakter versucht.
gegeben
import functools, itertools
f = functools.partial(itertools.permutations, r = 3)
def g(x,y,z):
return x + y == z
Dies sind 2 Zeichen weniger als das Original
any(g(*args) for args in f((a,b,c)))
Test mit:
assert any(g(*args) for args in f((a,b,c))) == (a + b == c or a + c == b or b + c == a)
zusätzlich gegeben:
h = functools.partial(itertools.starmap, g)
Das ist gleichwertig
any(h(f((a,b,c))))
g()
Sie definieren müssen, damit dies funktioniert. Angesichts all dessen würde ich sagen, dass es bedeutend größer ist.
Ich möchte das präsentieren, was ich als die pythonischste Antwort sehe :
def one_number_is_the_sum_of_the_others(a, b, c):
return any((a == b + c, b == a + c, c == a + b))
Der allgemeine Fall, nicht optimiert:
def one_number_is_the_sum_of_the_others(numbers):
for idx in range(len(numbers)):
remaining_numbers = numbers[:]
sum_candidate = remaining_numbers.pop(idx)
if sum_candidate == sum(remaining_numbers):
return True
return False
In Bezug auf das Zen von Python denke ich, dass die hervorgehobenen Aussagen mehr befolgt werden als aus anderen Antworten:
Das Zen von Python, von Tim Peters
Schön ist besser als hässlich.
Explizit ist besser als implizit.
Einfach ist besser als komplex.
Komplex ist besser als kompliziert.
Wohnung ist besser als verschachtelt.
Spärlich ist besser als dicht.
Lesbarkeit zählt.
Sonderfälle sind nicht speziell genug, um gegen die Regeln zu verstoßen.
Obwohl Praktikabilität die Reinheit übertrifft.
Fehler sollten niemals stillschweigend vergehen.
Sofern nicht ausdrücklich zum Schweigen gebracht.
Verweigern Sie angesichts von Zweideutigkeiten die Versuchung zu raten.
Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, dies zu tun.
Obwohl dieser Weg zunächst vielleicht nicht offensichtlich ist, es sei denn, Sie sind Niederländer.
Jetzt ist besser als nie.
Obwohl nie oft besser ist alsgerade jetzt.
Wenn die Implementierung schwer zu erklären ist, ist es eine schlechte Idee.
Wenn die Implementierung leicht zu erklären ist, ist dies möglicherweise eine gute Idee.
Namespaces sind eine großartige Idee - lasst uns mehr davon machen!
Als alte Gewohnheit meiner Programmierung denke ich, dass das Platzieren eines komplexen Ausdrucks in einer Klausel die Lesbarkeit folgendermaßen verbessern kann:
a == b+c or b == a+c or c == a+b
Plus ()
:
((a == b+c) or (b == a+c) or (c == a+b))
Und ich denke auch, dass die Verwendung von Mehrfachzeilen mehr Sinne wie diese ergeben kann:
((a == b+c) or
(b == a+c) or
(c == a+b))
Im Allgemeinen
m = a+b-c;
if (m == 0 || m == 2*a || m == 2*b) do_stuff ();
Wenn das Bearbeiten einer Eingabevariablen für Sie in Ordnung ist,
c = a+b-c;
if (c==0 || c == 2*a || c == 2*b) do_stuff ();
Wenn Sie mit Bit-Hacks ausnutzen möchten, können Sie "!", ">> 1" und "<< 1" verwenden.
Ich habe die Division vermieden, obwohl dadurch zwei Multiplikationen vermieden werden können, um Rundungsfehler zu vermeiden. Überprüfen Sie jedoch, ob Überläufe vorliegen
def any_sum_of_others (*nums):
num_elements = len(nums)
for i in range(num_elements):
discriminating_map = map(lambda j: -1 if j == i else 1, range(num_elements))
if sum(n * u for n, u in zip(nums, discriminating_map)) == 0:
return True
return False
print(any_sum_of_others(0, 0, 0)) # True
print(any_sum_of_others(1, 2, 3)) # True
print(any_sum_of_others(7, 12, 5)) # True
print(any_sum_of_others(4, 2, 2)) # True
print(any_sum_of_others(1, -1, 0)) # True
print(any_sum_of_others(9, 8, -4)) # False
print(any_sum_of_others(4, 3, 2)) # False
print(any_sum_of_others(1, 1, 1, 1, 4)) # True
print(any_sum_of_others(0)) # True
print(any_sum_of_others(1)) # False