@wwii Nie wykluczają się wzajemnie. Zobacz a = 0, b = 0, c = 0;)
Honza Brabec
1
Co powiedział @phresnel. Zamiast próbować „uprościć” wyrażenie, opakuj je w funkcję o opisowej nazwie.
Głowonóg
Odpowiedzi:
206
Jeśli spojrzymy na Zen Pythona, podkreśl moje:
Zen Pythona - Tim Peters
Piękne jest lepsze niż brzydkie.
Jawne jest lepsze niż niejawne. Proste jest lepsze niż złożone.
Złożone jest lepsze niż skomplikowane.
Płaskie jest lepsze niż zagnieżdżone.
Rzadkie jest lepsze niż gęste. Liczy się czytelność.
Specjalne przypadki nie są na tyle wyjątkowe, aby łamać zasady.
Chociaż praktyczność przewyższa czystość.
Błędy nigdy nie powinny przejść bezgłośnie.
Chyba że wyraźnie uciszono.
W obliczu niejasności odrzuć pokusę zgadywania. Powinien być jeden - a najlepiej tylko jeden - oczywisty sposób na zrobienie tego.
Chociaż na początku może to nie być oczywiste, chyba że jesteś Holendrem.
Teraz jest lepiej niż nigdy.
Chociaż nigdy nie jest często lepsze niżprawo teraz. Jeśli implementacja jest trudna do wyjaśnienia, to zły pomysł. Jeśli implementacja jest łatwa do wyjaśnienia, może to być dobry pomysł.
Przestrzenie nazw to świetny pomysł - zróbmy ich więcej!
Najbardziej Pythonowe rozwiązanie to takie, które jest najbardziej przejrzyste, najprostsze i najłatwiejsze do wyjaśnienia:
a + b == c or a + c == b or b + c == a
Co więcej, nie musisz nawet znać języka Python, aby zrozumieć ten kod! To takie proste. To bez zastrzeżeń najlepsze rozwiązanie. Wszystko inne to intelektualna masturbacja.
Co więcej, jest to prawdopodobnie również najlepsze rozwiązanie, ponieważ jest to jedyna ze wszystkich propozycji, która powoduje zwarcia. Jeśli a + b == cwykonuje się tylko jedno dodanie i porównanie.
Jeszcze lepiej, dodaj kilka nawiasów, aby intencja była krystalicznie jasna.
Bryan Oakley,
3
Zamiar jest już krystalicznie jasny bez nawiasów. Nawiasy utrudniałyby czytanie - dlaczego autor używa nawiasów, skoro pierwszeństwo już to obejmuje?
Miles Rout,
1
Jeszcze jedna uwaga dotycząca próby bycia zbyt sprytnym: możesz wprowadzić nieprzewidziane błędy, pomijając warunki, których nie brałeś pod uwagę. Innymi słowy, możesz pomyśleć, że Twoje nowe kompaktowe rozwiązanie jest równoważne, ale nie we wszystkich przypadkach. Jeśli nie ma ważnego powodu, aby kodować inaczej (wydajność, ograniczenia pamięci itp.), Przejrzystość jest najważniejsza.
Rob Craig,
To zależy od tego, do czego służy formuła. Spójrz na „Jawne jest lepsze niż niejawne”, może być tak, że podejście „najpierw sortowanie” jaśniej wyraża to, co robi program, lub jedno z pozostałych. Myślę, że nie możemy oceniać na podstawie pytania.
Każdy, kto czyta ten kod, prawdopodobnie przeklnie cię za bycie „sprytnym”.
Karoly Horvath
5
@SilvioMayolo To samo dotyczy oryginału
Izkata
1
@AlexVarga, „Chodziło mi o to, że faktycznie odpowiedziałem na jego pytanie”. Zrobiłeś; używa o 30% mniej znaków (wstawia spacje między operatorami). Nie próbowałem powiedzieć, że twoja odpowiedź była błędna, tylko komentowałem, jak idiomatyczne (pytoniczne) jest. Niezła odpowiedź.
Paul Draper
54
Python ma anyfunkcję, która wykonuje operacje orna wszystkich elementach sekwencji. Tutaj przekonwertowałem twoje oświadczenie na krotkę 3-elementową.
any((a + b == c, a + c == b, b + c == a))
Zwróć uwagę, że orjest to zwarcie, więc jeśli obliczenie indywidualnych warunków jest kosztowne, może być lepiej zachować oryginalną konstrukcję.
@ TigerhawkT3 Jednak nie w tym przypadku; trzy wyrażenia zostaną ocenione, zanim krotka istnieje, a krotka będzie istnieć anyjeszcze przed uruchomieniem.
poke
13
O, rozumiem. Myślę, że dzieje się tak tylko wtedy, gdy jest tam generator lub podobny leniwy iterator.
TigerhawkT3
4
anyi all„zewrzyj” proces sprawdzania iterowalności, którą otrzymają; ale jeśli ta iterowalna jest sekwencją, a nie generatorem, to została już w pełni oceniona przed wywołaniem funkcji .
Karl Knechtel,
Ma to tę zaletę, że łatwo jest podzielić na wiele wierszy (podwójne wcięcie argumentów any, pojedyncze wcięcie ):w ifinstrukcji), co bardzo pomaga w czytelności, gdy w
grę
40
Jeśli wiesz, że masz do czynienia tylko z liczbami dodatnimi, to zadziała i jest całkiem jasne:
a, b, c = sorted((a, b, c))if a + b == c:
do_stuff()
Jak powiedziałem, działa to tylko w przypadku liczb dodatnich; ale jeśli wiesz, że będą pozytywne, jest to bardzo czytelne rozwiązanie IMO, nawet bezpośrednio w kodzie, a nie w funkcji.
Mógłbyś to zrobić, co może wykonać trochę powtarzających się obliczeń; ale nie określiłeś skuteczności jako celu:
from itertools import permutations
if any(x + y == z for x, y, z in permutations((a, b, c),3)):
do_stuff()
Lub bez permutations()i możliwość wielokrotnych obliczeń:
if any(x + y == z for x, y, z in[(a, b, c),(a, c, b),(b, c, a)]:
do_stuff()
Prawdopodobnie umieściłbym to lub jakiekolwiek inne rozwiązanie w funkcji. Następnie możesz po prostu czysto wywołać funkcję w swoim kodzie.
Osobiście, jeśli nie potrzebowałbym większej elastyczności od kodu, użyłbym tylko pierwszej metody w twoim pytaniu. To proste i wydajne. Nadal mógłbym umieścić to w funkcji:
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()
To całkiem Pythonic i jest to prawdopodobnie najbardziej efektywny sposób na zrobienie tego (pomijając dodatkowe wywołanie funkcji); chociaż i tak nie powinieneś martwić się zbytnio o wydajność, chyba że faktycznie powoduje to problem.
zwłaszcza jeśli możemy założyć, że a, b, c są nieujemne.
cphlewis
Uważam, że wyrażenie „nie zawsze działa” jest trochę mylące. Pierwsze rozwiązanie działa tylko wtedy, gdy wiesz na pewno, że twoje liczby są nieujemne. Na przykład z (a, b, c) = (-3, -2, -1) masz a + b! = C, ale b + c = a. Podobne przypadki z (-1, 1, 2) i (-2, -1, 1).
numer użytkownika
@usernumber, wiesz, zauważyłem to wcześniej; nie wiem, dlaczego tego nie naprawiłem.
Cyphase
Twoje najlepsze rozwiązanie nie działa dla dużej klasy wejść, podczas gdy sugestia OP działa dla wszystkich wejść. Dlaczego „nie działa” bardziej Pythonic niż „działa”?
Barry
3
Ooh, pstryk. „ Jeśli wiesz, że masz do czynienia tylko z liczbami dodatnimi , to zadziała i jest całkiem czyste”. Wszystkie inne działają dla dowolnych liczb, ale jeśli wiesz, że masz do czynienia tylko z liczbami dodatnimi , górna jest bardzo czytelna / Pythonic IMO.
Cyphase
17
Jeśli będziesz używać tylko trzech zmiennych, to Twoja metoda początkowa:
a + b == c or a + c == b or b + c == a
Jest już bardzo pytoniczny.
Jeśli planujesz używać większej liczby zmiennych, zastosuj metodę rozumowania z:
a + b + c in(2*a,2*b,2*c)
Jest bardzo sprytny, ale zastanówmy się, dlaczego. Dlaczego to działa?
Cóż, dzięki prostej arytmetyce widzimy, że:
a + b = c
c = c
a + b + c == c + c ==2*c
a + b + c ==2*c
I to będzie musiał uznać za prawdziwe dla A, B lub C, co oznacza, że tak będzie równa 2*a, 2*blub 2*c. Będzie to prawdą dla dowolnej liczby zmiennych.
Więc dobrym sposobem na szybkie napisanie tego byłoby po prostu sporządzenie listy swoich zmiennych i porównanie ich sumy z listą podwojonych wartości.
values =[a,b,c,d,e,...]
any(sum(values)in[2*x for x in values])
W ten sposób, aby dodać więcej zmiennych do równania, wszystko, co musisz zrobić, to edytować listę wartości za pomocą „n” nowych zmiennych, a nie pisać „n” równań
Co a=-1, b=-1, c=-2, a następnie a+b=c, ale a+b+c = -4i 2*max(a,b,c)to-2
Eric Renouf
Dziękuję, że to prawda, musiałbym użyć abs. Dokonywanie tej korekty teraz.
ThatGuyRussell
2
Po obsypaniu go pół tuzinem abs()wywołań, jest to Pythonic niż fragment OP (tak naprawdę nazwałbym go znacznie mniej czytelnym).
TigerhawkT3
To prawda, dostosuję to teraz
ThatGuyRussell
1
@ThatGuyRussell W celu zwarcia, chciałbyś użyć generatora ... coś takiego any(sum(values) == 2*x for x in values), w ten sposób nie musiałbyś robić całego podwajania z góry, tak jak jest to konieczne.
Barry
12
Poniższy kod może służyć do iteracyjnego porównywania każdego elementu z sumą pozostałych, która jest obliczana z sumy całej listy, z wyłączeniem tego elementu.
Fajnie :) Myślę, że jeśli usuniesz []nawiasy z drugiej linii to nawet zwarcie jak oryginał z or...
psmears 19.08.15
1
co jest w zasadzie any(a + b + c == 2*x for x in [a, b, c])dość bliskie sugestii PO
njzk2 Sierpnia
To jest podobne, ale ta metoda rozciąga się na dowolną liczbę zmiennych. Uwzględniłem sugestię @psmears dotyczącą zwarcia.
Arcanum
10
Nie próbuj tego upraszczać. Zamiast tego nazwij to, co robisz za pomocą funkcji:
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):...
Zastąpienie warunku czymś „sprytnym” może skrócić go, ale nie uczyni go bardziej czytelnym. Pozostawienie tego tak, jak jest, również nie jest zbyt czytelne, ponieważ trudno jest wiedzieć, dlaczego sprawdzasz te trzy warunki na pierwszy rzut oka. Dzięki temu jest absolutnie jasne, czego szukasz.
Jeśli chodzi o wydajność, to podejście dodaje narzut wywołania funkcji, ale nigdy nie poświęcaj czytelności dla wydajności, chyba że znalazłeś wąskie gardło, które absolutnie musisz naprawić. I zawsze mierz, ponieważ niektóre sprytne implementacje są w stanie zoptymalizować i wstawić niektóre wywołania funkcji w pewnych okolicznościach.
Funkcje należy pisać tylko wtedy, gdy spodziewasz się użyć tego samego kodu w więcej niż jednym miejscu lub jeśli kod jest złożony. W pierwotnym pytaniu nie ma wzmianki o ponownym wykorzystaniu kodu, a pisanie funkcji dla pojedynczej linii kodu jest nie tylko przesadą, ale w rzeczywistości pogarsza czytelność.
Igor Levicki
5
Pochodząc ze szkoły rzeczy FP, prawie całkowicie się z tym nie zgadzam i stwierdzam, że dobrze nazwane jednowierszowe funkcje są jednymi z najlepszych narzędzi zwiększających czytelność, jakie kiedykolwiek znajdziesz. Utwórz funkcję za każdym razem, gdy kroki, które podejmujesz, aby coś zrobić, nie od razu wyjaśniają to, co robisz, ponieważ nazwa funkcji pozwala określić, co jest lepsze niż jakikolwiek komentarz.
Jack
Bez względu na to, jaką szkołę przywołujesz, źle jest ślepo przestrzegać zestawu reguł. Konieczność przeskoczenia do innej części źródła w celu odczytania tej jednej linii kodu ukrytej wewnątrz funkcji tylko po to, aby móc zweryfikować, czy faktycznie robi to, co mówi w nazwie, a następnie konieczność przełączenia się z powrotem do miejsca wywołania funkcji Upewnij się, że przekazujesz prawidłowe parametry, jest to całkowicie niepotrzebne przełączanie kontekstu. Moim zdaniem utrudnia to zarówno czytelność, jak i przepływ pracy. Wreszcie, ani nazwa funkcji, ani komentarze do kodu nie zastępują dokumentacji kodu.
Igor Levicki
9
Python 3:
(a+b+c)/2in(a,b,c)(a+b+c+d)/2in(a,b,c,d)...
Skaluje się do dowolnej liczby zmiennych:
arr =[a,b,c,d,...]
sum(arr)/2in arr
Jednak generalnie zgadzam się, że jeśli nie masz więcej niż trzech zmiennych, oryginalna wersja jest bardziej czytelna.
Zwraca to nieprawidłowe wyniki dla niektórych danych wejściowych z powodu błędów zaokrąglania zmiennoprzecinkowego.
pkt
Należy unikać dzielenia ze względu na wydajność i dokładność.
Igor Levicki
1
@pts Czy żadna implementacja nie zwróci nieprawidłowych wyników z powodu zaokrąglania zmiennoprzecinkowego? Nawet a + b == c
osundblad
@osundblad: Jeśli a, b i c są liczbami int, to (a + b + c) / 2 zaokrągla (i może zwrócić nieprawidłowe wyniki), ale a + b == c jest dokładne.
pts
3
dzielenie przez 2 to po prostu zmniejszenie wykładnika o jeden, więc będzie dokładne dla każdej liczby całkowitej mniejszej niż 2 ^ 53 (część ułamkowa liczby zmiennoprzecinkowej w Pythonie), a dla większych liczb całkowitych można użyć dziesiętnych . Na przykład, aby sprawdzić liczby całkowite mniejsze niż 2 ^ 30, uruchom[x for x in range(pow(2,30)) if x != ((x * 2)/ pow(2,1))]
Vitalii Fedorenko
6
(a+b-c)*(a+c-b)*(b+c-a)==0
Jeśli suma dowolnych dwóch składników jest równa trzeciemu składnikowi, to jeden z czynników będzie wynosił zero, co spowoduje, że cały iloczyn będzie równy zero.
Myślałem dokładnie o tym samym, ale nie mogę zaprzeczyć, że jego oryginalna propozycja jest o wiele czystsza ...
user541686
@Mehrdad - Zdecydowanie. Naprawdę nie różni się od(a+b<>c) && (a+c<>b) && (b+c<>a) == false
mbeckish
Po prostu mnożenie jest droższe niż wyrażenia logiczne i podstawowa arytmetyka.
Igor Levicki,
@IgorLevicki - Tak, chociaż jest to BARDZO przedwczesny problem optymalizacji. Czy będzie to wykonywane dziesiątki tysięcy razy na sekundę? Jeśli tak, to prawdopodobnie chciałbyś spojrzeć na coś innego.
mbeckish
@mbeckish - Dlaczego uważasz, że jest to przedwczesne? Kod powinien być napisany z myślą o optymalizacji, a nie jako refleksja. Pewnego dnia jakiś stażysta skopiuje ten fragment kodu i wklei go do jakiejś pętli krytycznej dla wydajności na wbudowanej platformie, która będzie następnie działać na milionach urządzeń, niekoniecznie spowolnionych, ale być może marnując więcej energii baterii. Pisanie takiego kodu tylko zachęca do złych praktyk kodowania. Moim zdaniem OP powinien zapytać, czy istnieje sposób optymalizacji tego wyrażenia logicznego.
Igor Levicki
6
Może po prostu:
a == b + c or abs(a)== abs(b - c)
Zauważ, że to nie zadziała, jeśli zmienne są bez znaku.
Z punktu widzenia optymalizacji kodu (przynajmniej na platformie x86) wydaje się to być najbardziej wydajnym rozwiązaniem.
Nowoczesne kompilatory wbudowują wywołania funkcji abs () i unikają testowania znaków i późniejszej gałęzi warunkowej, używając sprytnej sekwencji instrukcji CDQ, XOR i SUB . Powyższy kod wysokiego poziomu będzie zatem reprezentowany tylko za pomocą instrukcji ALU o małym opóźnieniu, dużej przepustowości i tylko dwóch instrukcji warunkowych.
I myślę, że fabs()można to wykorzystać do floattypów;).
shA.t
4
Rozwiązanie dostarczone przez Alexa Vargę „a in (b + c, bc, cb)” jest zwarte i matematycznie piękne, ale nie pisałbym w ten sposób kodu, ponieważ następny programista nie zrozumiałby od razu celu kodu .
Rozwiązanie Mark Ransom dla
any((a + b == c, a + c == b, b + c == a))
jest bardziej jasny, ale niewiele bardziej zwięzły niż
a + b == c or a + c == b or b + c == a
Pisząc kod, któremu ktoś inny będzie musiał przyjrzeć się, lub na który będę musiał przyjrzeć się długo później, kiedy zapomniałem, o czym myślałem, kiedy go pisałem, bycie zbyt krótkim lub sprytnym powoduje więcej szkody niż pożytku. Kod powinien być czytelny. Tak zwięzły jest dobry, ale nie tak zwięzły, żeby następny programista nie mógł tego zrozumieć.
Szczere pytanie: dlaczego ludzie zawsze zakładają, że następny programista będzie idiotą niezdolnym do czytania kodu? Osobiście uważam ten pomysł za obraźliwy. Jeśli kod musi być napisany tak, aby był rażąco oczywisty dla każdego programisty, oznacza to, że jako zawód dbamy o najniższy wspólny mianownik, najmniej wykwalifikowany spośród nas. Jeśli nadal będziemy to robić, w jaki sposób mogą poprawić swoje umiejętności osobiste? Nie widzę tego w innych zawodach. Kiedy ostatnio widziałeś kompozytora piszącego prostą partyturę muzyczną tylko po to, aby każdy muzyk mógł ją zagrać, niezależnie od poziomu umiejętności?
Igor Levicki
6
Problem polega na tym, że nawet programiści mają ograniczoną energię umysłową, więc czy chcesz poświęcić swoją ograniczoną energię psychiczną na algorytm i aspekty programu wyższego poziomu, czy też na zastanowienie się, co oznacza jakiś skomplikowany wiersz kodu, kiedy można go wyrazić w prostszy sposób ? Programowanie jest trudne, więc nie utrudniaj mu niepotrzebnie, tak jak biegacz olimpijski nie przebiegłby wyścigu z ciężkim plecakiem tylko dlatego, że może. Jak mówi Steve McConell w Code Complete 2, czytelność jest jednym z najważniejszych aspektów kodu.
Paul J Abernathy
2
Żądanie jest bardziej zwarte LUB bardziej pythonowe - próbowałem swoich sił w bardziej zwartym.
dany
import functools, itertools
f = functools.partial(itertools.permutations, r =3)def g(x,y,z):return x + y == z
To o 2 znaki mniej niż oryginał
any(g(*args)for args in f((a,b,c)))
test z:
assert any(g(*args)for args in f((a,b,c)))==(a + b == c or a + c == b or b + c == a)
Cóż, jest o dwa znaki krótsze niż oryginał, ale nie ten, który dał OP zaraz potem, z którego, jak powiedział, obecnie korzysta. Oryginał zawiera również dużo białych znaków, które to pomija, gdy tylko jest to możliwe. Jest też mała kwestia funkcji, g()którą musisz zdefiniować, aby to zadziałało. Biorąc to wszystko pod uwagę, powiedziałbym, że jest znacznie większy.
TigerhawkT3
@ TigerhawkT3, zinterpretowałem to jako żądanie krótszego wyrażenia / wiersza. zobacz edycję dla dalszych ulepszeń .
wojna światowa
4
Bardzo złe nazwy funkcji, odpowiednie tylko dla kodu golfa.
0xc0de
@ 0xc0de - przepraszam, nie gram. Odpowiedni może być dość subiektywny i zależny od okoliczności - ale ograniczę się do społeczności.
wojna światowa
Nie rozumiem, jak to jest bardziej zwarte, gdy ma więcej znaków niż oryginalny kod.
Igor Levicki
1
Chcę przedstawić to, co uważam za najbardziej pytoniczną odpowiedź:
def one_number_is_the_sum_of_the_others(a, b, c):return any((a == b + c, b == a + c, c == a + b))
Jeśli chodzi o Zen Pythona, myślę, że podkreślone stwierdzenia są bardziej przestrzegane niż w przypadku innych odpowiedzi:
Zen Pythona - Tim Peters
Piękne jest lepsze niż brzydkie. Jawne jest lepsze niż niejawne. Proste jest lepsze niż złożone.
Złożone jest lepsze niż skomplikowane.
Płaskie jest lepsze niż zagnieżdżone.
Rzadkie jest lepsze niż gęste. Liczy się czytelność.
Specjalne przypadki nie są na tyle wyjątkowe, aby łamać zasady.
Chociaż praktyczność przewyższa czystość.
Błędy nigdy nie powinny przejść bezgłośnie.
Chyba że wyraźnie uciszono.
W obliczu niejasności odrzuć pokusę zgadywania.
Powinien być jeden - a najlepiej tylko jeden - oczywisty sposób na zrobienie tego.
Chociaż na początku może to nie być oczywiste, chyba że jesteś Holendrem.
Teraz jest lepiej niż nigdy.
Chociaż nigdy nie jest często lepsze niżprawo teraz.
Jeśli implementacja jest trudna do wyjaśnienia, to zły pomysł.
Jeśli implementacja jest łatwa do wyjaśnienia, może to być dobry pomysł.
Przestrzenie nazw to świetny pomysł - zróbmy ich więcej!
Zgodnie ze starym nawykiem mojego programowania, myślę, że umieszczanie złożonego wyrażenia po prawej stronie w klauzuli może uczynić ją bardziej czytelną w następujący sposób:
a == b+c or b == a+c or c == a+b
Plus ():
((a == b+c)or(b == a+c)or(c == a+b))
Myślę też, że używanie multilinii może wywołać więcej zmysłów, takich jak ten:
def any_sum_of_others (*nums):
num_elements = len(nums)for i in range(num_elements):
discriminating_map = map(lambda j:-1if j == i else1, range(num_elements))if sum(n * u for n, u in zip(nums, discriminating_map))==0:returnTruereturnFalseprint(any_sum_of_others(0,0,0))# Trueprint(any_sum_of_others(1,2,3))# Trueprint(any_sum_of_others(7,12,5))# Trueprint(any_sum_of_others(4,2,2))# Trueprint(any_sum_of_others(1,-1,0))# Trueprint(any_sum_of_others(9,8,-4))# Falseprint(any_sum_of_others(4,3,2))# Falseprint(any_sum_of_others(1,1,1,1,4))# Trueprint(any_sum_of_others(0))# Trueprint(any_sum_of_others(1))# False
Funkcje należy pisać tylko wtedy, gdy spodziewasz się użyć tego samego kodu w więcej niż jednym miejscu lub jeśli kod jest złożony. W pierwotnym pytaniu nie ma wzmianki o ponownym wykorzystaniu kodu, a pisanie funkcji dla pojedynczej linii kodu jest nie tylko przesadą, ale w rzeczywistości pogarsza czytelność.
Igor Levicki
Nie zgadzam się, że ogranicza to czytelność; jeśli wybierzesz odpowiednią nazwę, może to poprawić czytelność (ale nie przedstawiam jakości nazwy, którą wybrałem w tej odpowiedzi). Ponadto pomocne może być nadanie nazwy koncepcji, którą będziesz musiał wykonać, o ile będziesz zmuszony nadać dobre imię swojej funkcji. Funkcje są dobre. To, czy funkcjonalność jest wystarczająco złożona, aby skorzystać na jej zamknięciu w funkcji, jest subiektywnym osądem.
Odpowiedzi:
Jeśli spojrzymy na Zen Pythona, podkreśl moje:
Najbardziej Pythonowe rozwiązanie to takie, które jest najbardziej przejrzyste, najprostsze i najłatwiejsze do wyjaśnienia:
Co więcej, nie musisz nawet znać języka Python, aby zrozumieć ten kod! To takie proste. To bez zastrzeżeń najlepsze rozwiązanie. Wszystko inne to intelektualna masturbacja.
Co więcej, jest to prawdopodobnie również najlepsze rozwiązanie, ponieważ jest to jedyna ze wszystkich propozycji, która powoduje zwarcia. Jeśli
a + b == c
wykonuje się tylko jedno dodanie i porównanie.źródło
Rozwiązanie trzech równości dla:
źródło
Python ma
any
funkcję, która wykonuje operacjeor
na wszystkich elementach sekwencji. Tutaj przekonwertowałem twoje oświadczenie na krotkę 3-elementową.Zwróć uwagę, że
or
jest to zwarcie, więc jeśli obliczenie indywidualnych warunków jest kosztowne, może być lepiej zachować oryginalną konstrukcję.źródło
any()
iall()
zwarcie też.any
jeszcze przed uruchomieniem.any
iall
„zewrzyj” proces sprawdzania iterowalności, którą otrzymają; ale jeśli ta iterowalna jest sekwencją, a nie generatorem, to została już w pełni oceniona przed wywołaniem funkcji .any
, pojedyncze wcięcie):
wif
instrukcji), co bardzo pomaga w czytelności, gdy wJeśli wiesz, że masz do czynienia tylko z liczbami dodatnimi, to zadziała i jest całkiem jasne:
Jak powiedziałem, działa to tylko w przypadku liczb dodatnich; ale jeśli wiesz, że będą pozytywne, jest to bardzo czytelne rozwiązanie IMO, nawet bezpośrednio w kodzie, a nie w funkcji.
Mógłbyś to zrobić, co może wykonać trochę powtarzających się obliczeń; ale nie określiłeś skuteczności jako celu:
Lub bez
permutations()
i możliwość wielokrotnych obliczeń:Prawdopodobnie umieściłbym to lub jakiekolwiek inne rozwiązanie w funkcji. Następnie możesz po prostu czysto wywołać funkcję w swoim kodzie.
Osobiście, jeśli nie potrzebowałbym większej elastyczności od kodu, użyłbym tylko pierwszej metody w twoim pytaniu. To proste i wydajne. Nadal mógłbym umieścić to w funkcji:
To całkiem Pythonic i jest to prawdopodobnie najbardziej efektywny sposób na zrobienie tego (pomijając dodatkowe wywołanie funkcji); chociaż i tak nie powinieneś martwić się zbytnio o wydajność, chyba że faktycznie powoduje to problem.
źródło
Jeśli będziesz używać tylko trzech zmiennych, to Twoja metoda początkowa:
Jest już bardzo pytoniczny.
Jeśli planujesz używać większej liczby zmiennych, zastosuj metodę rozumowania z:
Jest bardzo sprytny, ale zastanówmy się, dlaczego. Dlaczego to działa?
Cóż, dzięki prostej arytmetyce widzimy, że:
I to będzie musiał uznać za prawdziwe dla A, B lub C, co oznacza, że tak będzie równa
2*a
,2*b
lub2*c
. Będzie to prawdą dla dowolnej liczby zmiennych.Więc dobrym sposobem na szybkie napisanie tego byłoby po prostu sporządzenie listy swoich zmiennych i porównanie ich sumy z listą podwojonych wartości.
W ten sposób, aby dodać więcej zmiennych do równania, wszystko, co musisz zrobić, to edytować listę wartości za pomocą „n” nowych zmiennych, a nie pisać „n” równań
źródło
a=-1
,b=-1
,c=-2
, a następniea+b=c
, alea+b+c = -4
i2*max(a,b,c)
to-2
abs()
wywołań, jest to Pythonic niż fragment OP (tak naprawdę nazwałbym go znacznie mniej czytelnym).any(sum(values) == 2*x for x in values)
, w ten sposób nie musiałbyś robić całego podwajania z góry, tak jak jest to konieczne.Poniższy kod może służyć do iteracyjnego porównywania każdego elementu z sumą pozostałych, która jest obliczana z sumy całej listy, z wyłączeniem tego elementu.
źródło
[]
nawiasy z drugiej linii to nawet zwarcie jak oryginał zor
...any(a + b + c == 2*x for x in [a, b, c])
dość bliskie sugestii PONie próbuj tego upraszczać. Zamiast tego nazwij to, co robisz za pomocą funkcji:
Zastąpienie warunku czymś „sprytnym” może skrócić go, ale nie uczyni go bardziej czytelnym. Pozostawienie tego tak, jak jest, również nie jest zbyt czytelne, ponieważ trudno jest wiedzieć, dlaczego sprawdzasz te trzy warunki na pierwszy rzut oka. Dzięki temu jest absolutnie jasne, czego szukasz.
Jeśli chodzi o wydajność, to podejście dodaje narzut wywołania funkcji, ale nigdy nie poświęcaj czytelności dla wydajności, chyba że znalazłeś wąskie gardło, które absolutnie musisz naprawić. I zawsze mierz, ponieważ niektóre sprytne implementacje są w stanie zoptymalizować i wstawić niektóre wywołania funkcji w pewnych okolicznościach.
źródło
Python 3:
Skaluje się do dowolnej liczby zmiennych:
Jednak generalnie zgadzam się, że jeśli nie masz więcej niż trzech zmiennych, oryginalna wersja jest bardziej czytelna.
źródło
[x for x in range(pow(2,30)) if x != ((x * 2)/ pow(2,1))]
Jeśli suma dowolnych dwóch składników jest równa trzeciemu składnikowi, to jeden z czynników będzie wynosił zero, co spowoduje, że cały iloczyn będzie równy zero.
źródło
(a+b<>c) && (a+c<>b) && (b+c<>a) == false
Może po prostu:
Zauważ, że to nie zadziała, jeśli zmienne są bez znaku.
Z punktu widzenia optymalizacji kodu (przynajmniej na platformie x86) wydaje się to być najbardziej wydajnym rozwiązaniem.
Nowoczesne kompilatory wbudowują wywołania funkcji abs () i unikają testowania znaków i późniejszej gałęzi warunkowej, używając sprytnej sekwencji instrukcji CDQ, XOR i SUB . Powyższy kod wysokiego poziomu będzie zatem reprezentowany tylko za pomocą instrukcji ALU o małym opóźnieniu, dużej przepustowości i tylko dwóch instrukcji warunkowych.
źródło
fabs()
można to wykorzystać dofloat
typów;).Rozwiązanie dostarczone przez Alexa Vargę „a in (b + c, bc, cb)” jest zwarte i matematycznie piękne, ale nie pisałbym w ten sposób kodu, ponieważ następny programista nie zrozumiałby od razu celu kodu .
Rozwiązanie Mark Ransom dla
jest bardziej jasny, ale niewiele bardziej zwięzły niż
Pisząc kod, któremu ktoś inny będzie musiał przyjrzeć się, lub na który będę musiał przyjrzeć się długo później, kiedy zapomniałem, o czym myślałem, kiedy go pisałem, bycie zbyt krótkim lub sprytnym powoduje więcej szkody niż pożytku. Kod powinien być czytelny. Tak zwięzły jest dobry, ale nie tak zwięzły, żeby następny programista nie mógł tego zrozumieć.
źródło
Żądanie jest bardziej zwarte LUB bardziej pythonowe - próbowałem swoich sił w bardziej zwartym.
dany
To o 2 znaki mniej niż oryginał
test z:
dodatkowo podane:
To jest równoważne
źródło
g()
którą musisz zdefiniować, aby to zadziałało. Biorąc to wszystko pod uwagę, powiedziałbym, że jest znacznie większy.Chcę przedstawić to, co uważam za najbardziej pytoniczną odpowiedź:
Ogólny przypadek, niezoptymalizowany:
Jeśli chodzi o Zen Pythona, myślę, że podkreślone stwierdzenia są bardziej przestrzegane niż w przypadku innych odpowiedzi:
źródło
Zgodnie ze starym nawykiem mojego programowania, myślę, że umieszczanie złożonego wyrażenia po prawej stronie w klauzuli może uczynić ją bardziej czytelną w następujący sposób:
Plus
()
:Myślę też, że używanie multilinii może wywołać więcej zmysłów, takich jak ten:
źródło
W ogólny sposób
jeśli manipulowanie zmienną wejściową jest dla Ciebie OK,
jeśli chcesz wykorzystać bit hacki, możesz użyć "!", ">> 1" i "<< 1"
Uniknąłem dzielenia, chociaż pozwala to na uniknięcie podwójnego mnożenia, aby uniknąć błędów zaokrągleń. Jednak sprawdź, czy nie ma przepełnień
źródło
źródło