ブール式を記述するためのよりコンパクトな方法またはpythonicな方法はありますか
a + b == c or a + c == b or b + c == a
思いついた
a + b + c in (2*a, 2*b, 2*c)
しかし、それは少し奇妙です。
ブール式を記述するためのよりコンパクトな方法またはpythonicな方法はありますか
a + b == c or a + c == b or b + c == a
思いついた
a + b + c in (2*a, 2*b, 2*c)
しかし、それは少し奇妙です。
回答:
Zen of Pythonを見てみると、次のことが強調されます。
禅のPython、ティム・ピーターズ
醜いよりも美しい方がいいです。
明示的は暗黙的よりも優れています。
シンプルは複雑よりも優れています。
複雑は複雑よりも優れています。
ネストよりもフラットの方が適しています。
疎は密よりも優れています。
読みやすさが重要です。
特別なケースは、ルールを破るほど特別なものではありません。
実用性は純粋さを上回りますが。
エラーがサイレントに渡ることはありません。
明示的に沈黙させない限り。
あいまいな状況に直面して、推測する誘惑を拒否してください。
それを行うには、明白な方法が1つ(できれば1つだけ)あるはずです。
あなたがオランダ人でない限り、その方法は最初は明白ではないかもしれませんが。
今は決してないよりはましです。
多くの場合、右今。
実装の説明が難しい場合は、悪い考えです。
実装が説明しやすい場合は、良いアイデアかもしれません。
名前空間は非常に魅力的なアイデアの1つです。もっと多くのことをしましょう。
最もPythonicなソリューションは、最も明確で、最も単純で、最も簡単に説明できるものです。
a + b == c or a + c == b or b + c == a
さらに良いことに、このコードを理解するのにPythonを知る必要さえありません!それはだことは簡単。これは、予約なしで最良のソリューションです。それ以外は知的オナニーです。
さらに、これは回路を短絡させるすべての提案の中の唯一のものであるため、これも同様に最もパフォーマンスの高いソリューションです。の場合a + b == c
、追加と比較は1回だけ行われます。
次の3つの等式を解く:
a in (b+c, b-c, c-b)
Pythonには、シーケンスのすべての要素に対してを実行するany
関数がありor
ます。ここでは、ステートメントを3要素のタプルに変換しました。
any((a + b == c, a + c == b, b + c == a))
注or
個々の条件を計算することは高価であるならば、それは良いかもしれない、あなたのオリジナルの構造を維持するため、短絡です。
any()
そしてall()
短絡も。
any
実行前に存在します。
any
そして、それらが与えられたイテラブルを検査するall
プロセスを「短絡」します。ただし、その反復可能オブジェクトがジェネレーターではなくシーケンスである場合、関数呼び出しが発生する前に完全に評価されています。
any
、シングルインデント):
でif
文)、数学が関与している時に、読みやすくするために多くを助けた
正の数のみを処理していることがわかっている場合、これは機能し、かなりクリーンです。
a, b, c = sorted((a, b, c))
if a + b == c:
do_stuff()
すでに述べたように、これは正の数に対してのみ機能します。しかし、それらがポジティブになることがわかっている場合、これは非常に読みやすいソリューションIMOです。これは、関数ではなくコード内で直接です。
これを行うと、少し繰り返し計算が行われる可能性があります。しかし、目標としてパフォーマンスを指定しませんでした:
from itertools import permutations
if any(x + y == z for x, y, z in permutations((a, b, c), 3)):
do_stuff()
またはpermutations()
、計算を繰り返さなくても可能です。
if any(x + y == z for x, y, z in [(a, b, c), (a, c, b), (b, c, a)]:
do_stuff()
私はおそらくこれまたは他の解決策を関数に入れます。次に、コードで関数をきれいに呼び出すことができます。
個人的には、コードにもっと柔軟性が必要でない限り、質問の最初の方法を使用します。シンプルで効率的です。私はまだそれを関数に入れるかもしれません:
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()
それはかなりPythonicであり、それを行うにはおそらく最も効率的な方法です(追加の関数呼び出しは別として)。とにかく、実際に問題を引き起こしていない限り、パフォーマンスについてあまり気にする必要はありません。
3つの変数のみを使用する場合、最初の方法は次のとおりです。
a + b == c or a + c == b or b + c == a
すでに非常にpythonicです。
より多くの変数を使用することを計画しているなら、あなたの推論の方法は:
a + b + c in (2*a, 2*b, 2*c)
とても賢いですが、その理由を考えてみましょう。なぜこれが機能するのですか?
いくつかの簡単な算術を通して、次のことがわかります。
a + b = c
c = c
a + b + c == c + c == 2*c
a + b + c == 2*c
そして、これはイエスが、それが等しくなることを意味し、いずれかのA、B、またはCのための真の保持する必要があります2*a
、2*b
または2*c
。これは、任意の数の変数に当てはまります。
したがって、これをすばやく書くための良い方法は、変数のリストを用意し、その合計を2倍の値のリストと照合することです。
values = [a,b,c,d,e,...]
any(sum(values) in [2*x for x in values])
このように、方程式にさらに変数を追加するには、「n」個の方程式を記述するのではなく、「n」個の新しい変数で値リストを編集するだけです。
a=-1
、b=-1
、c=-2
、そしてa+b=c
、しかし、a+b+c = -4
と2*max(a,b,c)
ある-2
abs()
呼び出しでそれをペパリングした後、それはOPのスニペットよりもPythonicです(私は実際にはそれを大幅に読みにくくします)。
any(sum(values) == 2*x for x in values)
、必要に応じて、前もってすべてのダブリングを行う必要はありません。
次のコードを使用すると、各要素を、その要素を除くリスト全体の合計から計算される他の要素の合計と繰り返し比較できます。
l = [a,b,c]
any(sum(l)-e == e for e in l)
[]
2行目からブラケットを削除すると、元のように短絡することもあると思いますor
...
any(a + b + c == 2*x for x in [a, b, c])
に、OPの提案にかなり近い
それを試して簡素化しないでください。代わりに、関数で何をしているのか名前を付けます。
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):
...
条件を「賢い」もので置き換えると短くなる可能性がありますが、読みやすくなるわけではありません。しかし、それをそのままにしておくことは、あまり読みにくいです。理由を知るのは難しいためです。この3つの条件をひと目で確認。これにより、何をチェックしているかが完全に明確になります。
パフォーマンスに関しては、このアプローチは関数呼び出しのオーバーヘッドを追加しますが、絶対に修正する必要があるボトルネックを見つけない限り、パフォーマンスの読みやすさを犠牲にすることはありません。また、状況に応じて一部の関数呼び出しを最適化してインライン化できる巧妙な実装があるため、常に測定してください。
Python 3:
(a+b+c)/2 in (a,b,c)
(a+b+c+d)/2 in (a,b,c,d)
...
任意の数の変数にスケーリングします。
arr = [a,b,c,d,...]
sum(arr)/2 in arr
ただし、一般に、4つ以上の変数がない限り、元のバージョンの方が読みやすいことに同意します。
[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
2つの項の合計が3番目の項と等しい場合、因子の1つがゼロになり、積全体がゼロになります。
(a+b<>c) && (a+c<>b) && (b+c<>a) == false
どうですか:
a == b + c or abs(a) == abs(b - c)
変数が符号なしの場合、これは機能しないことに注意してください。
コードの最適化の観点から(少なくともx86プラットフォームでは)、これは最も効率的なソリューションのようです。
最新のコンパイラーは、両方のabs()関数呼び出しをインライン化し、CDQ、XOR、およびSUB命令の巧妙なシーケンスを使用することにより、符号テストおよび後続の条件分岐を回避します。したがって、上記の高レベルコードは、低レイテンシ、高スループットのALU命令と2つの条件のみで表されます。
fabs()
はfloat
タイプに使用できると思います;)
Alex Vargaが提供するソリューション「a in(b + c、bc、cb)」はコンパクトで数学的に美しいですが、次の開発者がコードの目的をすぐに理解できないため、実際にはそのようにコードを記述しません。 。
マーク・ランサムのソリューション
any((a + b == c, a + c == b, b + c == a))
より明確ですが、それほど簡潔ではありません
a + b == c or a + c == b or b + c == a
他の誰かが見なければならないコードを書くとき、または私がそれを書いたときに私が考えていたことを忘れてしまったときに、後でずっと見なければならないコードを書くとき、短すぎるか賢いことは、善よりも害を及ぼす傾向があります。コードは読み取り可能でなければなりません。したがって、簡潔であるのは良いですが、次のプログラマが理解できないほど簡潔ではありません。
リクエストは、よりコンパクトな、またはよりパイソンのようなものです-私はもっとコンパクトで手を試してみました。
与えられた
import functools, itertools
f = functools.partial(itertools.permutations, r = 3)
def g(x,y,z):
return x + y == z
これはオリジナルより2文字少ない
any(g(*args) for args in f((a,b,c)))
テスト:
assert any(g(*args) for args in f((a,b,c))) == (a + b == c or a + c == b or b + c == a)
さらに、与えられた:
h = functools.partial(itertools.starmap, g)
これは同等です
any(h(f((a,b,c))))
g()
するために定義しなければならない関数の小さな問題もあります。それを考えると、かなり大きいと思います。
私は最もパイソン的な答えとして私が見るものを提示したいと思います:
def one_number_is_the_sum_of_the_others(a, b, c):
return any((a == b + c, b == a + c, c == a + b))
最適化されていない一般的なケース:
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
Zen of Pythonに関して、強調されたステートメントは他の回答よりもフォローされていると思います。
禅のPython、ティム・ピーターズ
醜いよりも美しい方がいいです。
明示的は暗黙的よりも優れています。
シンプルは複雑よりも優れています。
複雑は複雑よりも優れています。
ネストよりもフラットの方が優れています。
疎は密よりも優れています。
読みやすさが重要です。
特別なケースは、ルールを破るほど特別なものではありません。
実用性は純粋さを上回りますが。
エラーがサイレントに渡ることはありません。
明示的に沈黙させない限り。
あいまいな状況に直面して、推測する誘惑を拒否してください。
それを行うには、明白な方法が1つ(できれば1つだけ)あるはずです。
あなたがオランダ人でない限り、その方法は最初は明白ではないかもしれませんが。
今は決してないよりはましです。
多くの場合、右今。
実装の説明が難しい場合は、悪い考えです。
実装が説明しやすい場合は、良いアイデアかもしれません。
名前空間は非常に魅力的なアイデアの1つです。もっと多くのことをしましょう。
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