Boole ifadesini yazmanın daha kompakt veya pythonic bir yolu var mı
a + b == c or a + c == b or b + c == a
İle geldim
a + b + c in (2*a, 2*b, 2*c)
ama bu biraz garip.
Boole ifadesini yazmanın daha kompakt veya pythonic bir yolu var mı
a + b == c or a + c == b or b + c == a
İle geldim
a + b + c in (2*a, 2*b, 2*c)
ama bu biraz garip.
Yanıtlar:
Python'un Zen'ine bakarsak, benimkini vurgulayın:
Python'un Zen'i, Tim Peters
Güzel, çirkin olmaktan iyidir.
Açık, örtük olmaktan iyidir.
Basit, karmaşık olmaktan iyidir.
Karmaşık karmaşık olmaktan iyidir.
Düz iç içe geçmişten daha iyidir.
Seyrek yoğun olmaktan iyidir.
Okunabilirlik önemlidir.
Özel durumlar kuralları ihlal edecek kadar özel değildir.
Pratiklik saflığı yenmesine rağmen.
Hatalar asla sessizce geçmemelidir.
Açıkça susturulmadıkça.
Belirsizlik karşısında, tahmin etme isteğini reddet.
Bunu yapmanın tek ve tercihen tek bir yolu olmalı.
Her ne kadar Hollandalı değilseniz bu yol ilk başta belli olmayabilir.
Şimdi hiç olmadığı kadar iyi.
Her ne kadar asla genellikle daha iyi olmasa daSağ şimdi.
Uygulamanın açıklanması zorsa, bu kötü bir fikirdir.
Uygulamanın açıklanması kolaysa, iyi bir fikir olabilir.
İsim alanları harika bir fikirdir - bunlardan daha fazlasını yapalım!
En Pythonic çözümü en açık, en basit ve açıklanması en kolay çözümdür:
a + b == c or a + c == b or b + c == a
Daha da iyisi, bu kodu anlamak için Python'u bilmenize bile gerek yok! Bu kadar kolay. Bu, çekincesiz, en iyi çözümdür. Başka bir şey entelektüel mastürbasyon.
Ayrıca, kısa devreleri olan tüm tekliflerden sadece biri olduğu için bu muhtemelen en iyi performans gösteren çözümdür. Eğer a + b == csadece tek bir ekleme ve karşılaştırma yapılır.
Üç eşitliği aşağıdakiler için çözme:
a in (b+c, b-c, c-b)
Python, bir dizinin tüm elemanlarında bir anyfonksiyona sahiptir or. Burada ifadenizi 3 elemanlı bir gruba dönüştürdüm.
any((a + b == c, a + c == b, b + c == a))
orKısa devre olduğunu unutmayın , bu nedenle bireysel koşulları hesaplamak pahalıysa, orijinal yapınızı korumak daha iyi olabilir.
any()ve all()kısa devre de.
anyçift çalıştırmadan önce var olur .
anyve all"kısa devre" verildikleri yinelemeyi inceleme süreci ; ancak bu yinelenebilir bir jeneratörden ziyade bir sekans ise , fonksiyon çağrısı gerçekleşmeden önce tam olarak değerlendirilmiştir .
anytek girintili olma ) ):if
Yalnızca pozitif sayılarla uğraştığınızı biliyorsanız, bu işe yarayacak ve oldukça temiz:
a, b, c = sorted((a, b, c))
if a + b == c:
do_stuff()
Dediğim gibi, bu sadece pozitif sayılar için geçerlidir; ancak pozitif olacaklarını biliyorsanız , bu, bir fonksiyonun aksine doğrudan kodda bile çok okunabilir bir çözüm IMO'sudur.
Biraz tekrarlanan hesaplama yapabilen bunu yapabilirsiniz; ancak performansı hedefiniz olarak belirtmediniz:
from itertools import permutations
if any(x + y == z for x, y, z in permutations((a, b, c), 3)):
do_stuff()
Veya olmadan permutations()ve tekrarlanan hesaplamalar olasılığı:
if any(x + y == z for x, y, z in [(a, b, c), (a, c, b), (b, c, a)]:
do_stuff()
Muhtemelen bunu ya da başka bir çözümü bir fonksiyona koyardım. Daha sonra kodunuzdaki işlevi temiz bir şekilde çağırabilirsiniz.
Şahsen, koddan daha fazla esnekliğe ihtiyaç duymadıkça, sorunuzdaki ilk yöntemi kullanacağım. Çok basit ve etkili. Yine de bir işleve koyabilirim:
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()
Bu oldukça Pythonic ve muhtemelen bunu yapmanın en etkili yolu (ekstra fonksiyon bir kenara çağırmak); yine de performans hakkında çok fazla endişelenmemelisiniz, aslında bir soruna neden olmadıkça.
Yalnızca üç değişken kullanacaksanız, ilk yönteminiz:
a + b == c or a + c == b or b + c == a
Zaten çok pitonik.
Daha fazla değişken kullanmayı planlıyorsanız, mantık yönteminiz:
a + b + c in (2*a, 2*b, 2*c)
Çok akıllı ama nedenini düşünelim. Bu neden işe yarıyor?
Bazı basit aritmetik sayesinde şunu görüyoruz:
a + b = c
c = c
a + b + c == c + c == 2*c
a + b + c == 2*c
Ve bu o evet o eşit olur yani biri a, b veya c için geçerli zorunda kalacak 2*a, 2*bya 2*c. Bu, herhangi bir sayıda değişken için geçerli olacaktır.
Bunu hızlı bir şekilde yazmanın iyi bir yolu, değişkenlerinizin bir listesine sahip olmak ve toplamlarını iki katına çıkmış değerlerin bir listesiyle karşılaştırmak olacaktır.
values = [a,b,c,d,e,...]
any(sum(values) in [2*x for x in values])
Bu şekilde, denkleme daha fazla değişken eklemek için tek yapmanız gereken değerler listenizi 'n' denklemleri yazmak yerine 'n' yeni değişkenlere göre düzenlemek
a=-1, b=-1, c=-2, daha sonra a+b=c, ancak a+b+c = -4ve 2*max(a,b,c)bir-2
abs()çağrı ile biberledikten sonra , OP'nin snippet'inden Pythonic (aslında daha az okunabilir diyebilirim).
any(sum(values) == 2*x for x in values), bu şekilde gerekli olan tüm ikiye katlamayı yapmak zorunda kalmazsınız.
Aşağıdaki kod, her bir öğeyi, o öğe hariç olmak üzere, tüm listenin toplamından hesaplanan diğerlerinin toplamı ile tekrarlı olarak karşılaştırmak için kullanılabilir.
l = [a,b,c]
any(sum(l)-e == e for e in l)
[]ikinci satırdan parantez kaldırırsanız , bu bile orijinal gibi kısa devre olacak or...
any(a + b + c == 2*x for x in [a, b, c])OP'nin önerisine oldukça yakın
Deneyin ve basitleştirmeyin. Bunun yerine, isim , bir işlevle yapıyoruz:
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):
...
Koşulu "zekice" bir şeyle değiştirmek, onu kısaltabilir, ancak daha okunabilir hale getirmez. Bununla birlikte, onu nasıl bıraktığınız da çok okunabilir değil, çünkü bu üç koşulu bir bakışta neden kontrol ettiğinizi bilmek zor . Bu, ne kontrol ettiğinizi kesinlikle netleştirir.
Performansla ilgili olarak, bu yaklaşım bir işlev çağrısının ek yükünü ekler, ancak kesinlikle düzeltmeniz gereken bir darboğaz bulmadıkça performans için okunabilirliği asla feda etmeyin. Ve her zaman ölçün, çünkü bazı akıllı uygulamalar bazı durumlarda bazı işlev çağrılarını optimize etme ve satır içine alma yeteneğine sahiptir.
Python 3:
(a+b+c)/2 in (a,b,c)
(a+b+c+d)/2 in (a,b,c,d)
...
Herhangi bir sayıda değişkene göre ölçeklendirilir:
arr = [a,b,c,d,...]
sum(arr)/2 in arr
Ancak, genel olarak, üçten fazla değişkeniniz olmadıkça, orijinal sürümün daha okunabilir olduğunu kabul ediyorum.
[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
İki terimin toplamı üçüncü terime eşitse, faktörlerden biri sıfır olur ve tüm ürün sıfırlanır.
(a+b<>c) && (a+c<>b) && (b+c<>a) == false
Peki ya:
a == b + c or abs(a) == abs(b - c)
Değişkenler imzalanmamışsa bunun işe yaramayacağını unutmayın.
Kod optimizasyonu açısından (en azından x86 platformunda) bu en etkili çözüm gibi görünüyor.
Modern derleyiciler, hem abs () işlev çağrılarını satır içine alacak ve akıllı bir CDQ, XOR ve SUB komut dizisi kullanarak işaret testini ve sonraki koşullu dalı önleyecektir . Yukarıdaki yüksek seviye kodu bu nedenle sadece düşük gecikmeli, yüksek verimli ALU talimatları ve sadece iki koşulla temsil edilecektir.
fabs()için kullanılabilir float;).
Alex Varga tarafından sağlanan çözüm (b + c, bc, cb) "kompakt ve matematiksel olarak güzel, ama aslında bu şekilde kod yazmayacağım çünkü bir sonraki geliştirici, kodun amacını hemen anlayamayacaktı .
Mark Ransom'un çözümü
any((a + b == c, a + c == b, b + c == a))
daha açık ama daha özlü değil
a + b == c or a + c == b or b + c == a
Başka birinin bakması gerekecek ya da yazarken ne düşündüğümü unuttuğumda uzun süre bakmak zorunda kalacağım kodu yazarken, çok kısa ya da zeki olmak yarardan çok zarar verme eğilimindedir. Kod okunabilir olmalıdır. Çok özlü, ama bir sonraki programcı bunu anlayamayacak kadar özlü değil.
Talep daha kompakt VEYA daha pitonik için - elimi daha kompakt denedim.
verilmiş
import functools, itertools
f = functools.partial(itertools.permutations, r = 3)
def g(x,y,z):
return x + y == z
Bu orijinalden 2 karakter daha az
any(g(*args) for args in f((a,b,c)))
ile test:
assert any(g(*args) for args in f((a,b,c))) == (a + b == c or a + c == b or b + c == a)
ayrıca, verilen:
h = functools.partial(itertools.starmap, g)
Bu eşdeğerdir
any(h(f((a,b,c))))
g()için tanımlamanız gereken fonksiyonun küçük bir konusu da vardır . Tüm bunlar göz önüne alındığında, önemli ölçüde daha büyük olduğunu söyleyebilirim.
En pitonik cevap olarak gördüğümü sunmak istiyorum :
def one_number_is_the_sum_of_the_others(a, b, c):
return any((a == b + c, b == a + c, c == a + b))
Optimize edilmemiş genel durum:
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
Python Zen açısından, vurgulanan ifadelerin diğer cevaplardan daha fazla takip edildiğini düşünüyorum:
Python'un Zen'i, Tim Peters
Güzel, çirkin olmaktan iyidir.
Açık, örtük olmaktan iyidir.
Basit, karmaşık olmaktan iyidir.
Karmaşık karmaşık olmaktan iyidir.
Düz iç içe geçmişten daha iyidir.
Seyrek yoğun olmaktan iyidir.
Okunabilirlik önemlidir.
Özel durumlar kuralları ihlal edecek kadar özel değildir.
Pratiklik saflığı yenmesine rağmen.
Hatalar asla sessizce geçmemelidir.
Açıkça susturulmadıkça.
Belirsizlik karşısında, tahmin etme isteğini reddet.
Bunu yapmanın tek ve tercihen tek bir yolu olmalı.
Her ne kadar Hollandalı değilseniz bu yol ilk başta belli olmayabilir.
Şimdi hiç olmadığı kadar iyi.
Her ne kadar asla genellikle daha iyi olmasa daSağ şimdi.
Uygulamanın açıklanması zorsa, bu kötü bir fikirdir.
Uygulamanın açıklanması kolaysa, iyi bir fikir olabilir.
İsim alanları harika bir fikirdir - hadi bunlardan daha fazlasını yapalım!
Programlamamın eski bir alışkanlığı olarak, karmaşık ifadeyi sağda bir cümle içine yerleştirmenin onu daha okunabilir hale getirebileceğini düşünüyorum:
a == b+c or b == a+c or c == a+b
Artı ():
((a == b+c) or (b == a+c) or (c == a+b))
Ve ayrıca çok satırlı kullanımın daha fazla mantıklı olabileceğini düşünüyorum:
((a == b+c) or
(b == a+c) or
(c == a+b))
Genel bir şekilde,
m = a+b-c;
if (m == 0 || m == 2*a || m == 2*b) do_stuff ();
bir giriş değişkenini değiştirmek sizin için uygunsa,
c = a+b-c;
if (c==0 || c == 2*a || c == 2*b) do_stuff ();
bit kesmek kullanarak yararlanmak istiyorsanız, "!", ">> 1" ve "<< 1" kullanabilirsiniz.
Yuvarlama hatalarını önlemek için iki çarpmayı önlemek için kullanılmasına rağmen bölünmeden kaçındım. Ancak taşmaları kontrol edin
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