ブール式を記述するためのよりコンパクトなまたはPythonの方法はありますか
a + b == c or a + c == b or b + c == a
思いついた
a + b + c in (2*a, 2*b, 2*c)
しかし、それは少し奇妙です。
PythonのZenを見ると、次の点を強調しています。
Pythonの禅、ティムピーターズ著
いよりも美しいほうがいい。
明示的は暗黙的よりも優れています。
単純なものは複雑なものよりも優れています。
複雑さは複雑さよりも優れています。
Flatはネストよりも優れています。
スパースは、デンスよりも優れています。
可読性カウント
特別なケースは、ルールを破るほど特別ではありません。
実用性は純度よりも優れていますが。
エラーが静かに渡されることはありません。
明示的に沈黙しない限り。
あいまいさに直面して、推測する誘惑を拒否します。
1つある必要があります-できれば1つだけ-明白な方法です。
オランダ人でない限り、その方法は最初は明らかではないかもしれませんが。
今では、これまで以上に優れています。
多くの場合、rightよりも優れていることはありません。
実装の説明が難しい場合、それは悪い考えです。
実装の説明が簡単な場合は、良いアイデアかもしれません。
名前空間は素晴らしいアイデアの1つです。それらをさらに活用しましょう。
最もPythonyのソリューションは、最も明確で、シンプルで、説明が簡単なソリューションです。
a + b == c or a + c == b or b + c == a
さらに良いことに、このコードを理解するためにPythonを知っている必要さえありません!that簡単です。知的オナニー。
さらに、これは、短絡するすべての提案の中で唯一のものであるため、おそらく最高のパフォーマンスのソリューションでもあります。 a + b == c
、単一の加算と比較のみが行われます。
Aの3つの等式を解く:
a in (b+c, b-c, c-b)
Pythonには、シーケンスのすべての要素に対してany
を実行するor
関数があります。ここで、ステートメントを3要素のタプルに変換しました。
any((a + b == c, a + c == b, b + c == a))
or
は短絡であるため、個々の条件の計算に費用がかかる場合は、元の構造を保持する方がよい場合があることに注意してください。
正の数のみを処理していることがわかっている場合、これは動作し、かなりきれいです:
_a, b, c = sorted((a, b, c))
if a + b == c:
do_stuff()
_
私が言ったように、これは正の数に対してのみ機能します。しかしknowがポジティブになる場合、これは非常に読みやすいソリューション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」個の新しい変数で値リストを編集するだけです。
次のコードは、各要素を他の要素の合計と繰り返し比較するために使用できます。他の要素の合計は、その要素を除くリスト全体の合計から計算されます。
l = [a,b,c]
any(sum(l)-e == e for e in l)
簡単にしようとしないでください。代わりに、name関数で何をしているのか:
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):
...
条件を「賢い」何かに置き換えると、短くなりますが、読みやすくなりません。ただし、その方法をそのままにしておくことは、非常に読みやすいものではありません。これは、whyの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
ただし、一般に、3つ以上の変数がない限り、元のバージョンの方が読みやすいことに同意します。
どうですか:
a == b + c or abs(a) == abs(b - c)
変数が符号なしの場合、これは機能しないことに注意してください。
コードの最適化の観点から(少なくともx86プラットフォームで)これは最も効率的なソリューションであるようです。
最新のコンパイラは、abs()関数呼び出しの両方をインライン化し、 CDQ、XOR、およびSUB命令の巧妙なシーケンス を使用することにより、符号テストとそれに続く条件分岐を回避します。したがって、上記の高レベルコードは、低レイテンシ、高スループットのALU命令と2つの条件のみで表されます。
(a+b-c)*(a+c-b)*(b+c-a) == 0
2つの項の合計が3番目の項に等しい場合、因子の1つがゼロになり、製品全体がゼロになります。
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
他の誰かが見なければならないコードを書くとき、または私がそれを書いたときに私が考えていたことを忘れてしまったとき、私は長い時間を見なければならないコードを書くとき、短すぎるか賢いことは良いことよりも害を及ぼす傾向があります。コードは読み取り可能である必要があります。簡潔で良いのですが、次のプログラマが理解できないほど簡潔ではありません。
リクエストは、よりコンパクトなORもっとPythonic-よりコンパクトに手を試しました。
与えられた
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))))
私のプログラミングの古い習慣として、句の右側に複雑な式を配置すると、次のように読みやすくなると思います。
a == b+c or b == a+c or c == a+b
プラス()
:
((a == b+c) or (b == a+c) or (c == a+b))
また、複数行を使用すると、次のような意味が生まれると思います。
((a == b+c) or
(b == a+c) or
(c == a+b))
私が最も見ているものを提示したいPythonic答え:
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
PythonのZenに関しては、強調されたステートメントは他の答えからよりも追随していると思います。
Pythonの禅、ティムピーターズ著
いよりも美しいほうがいい。
明示的は暗黙的よりも優れています。
単純なものは複雑なものよりも優れています。
複雑さは複雑さよりも優れています。
Flatはネストよりも優れています。
スパースは、デンスよりも優れています。
可読性カウント
特別なケースは、ルールを破るほど特別ではありません。
実用性は純度よりも優れていますが。
エラーが静かに渡されることはありません。
明示的に沈黙しない限り。
あいまいさに直面して、推測する誘惑を拒否します。
それを行うための明白な方法は、1つ(できれば1つだけ)でなければなりません。
オランダ人でない限り、その方法は最初は明らかではないかもしれませんが。
今では、これまで以上に優れています。
多くの場合、rightよりも優れていることはほとんどありません。
実装の説明が難しい場合、それは悪い考えです。
実装の説明が簡単な場合は、良いアイデアかもしれません。
名前空間は素晴らしいアイデアの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
一般的な方法で、
m = a+b-c;
if (m == 0 || m == 2*a || m == 2*b) do_stuff ();
入力変数を操作しても問題ない場合、
c = a+b-c;
if (c==0 || c == 2*a || c == 2*b) do_stuff ();
ビットハックを使用して悪用したい場合は、「!」、「>> 1」、「<< 1」を使用できます
除算を回避しましたが、2つの乗算を回避して丸め誤差を回避するために使用できます。ただし、オーバーフローを確認してください