3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

「全て異なる」という条件をPythonで実験する

Last updated at Posted at 2021-01-29

はじめに

「a, b, cは全て異なる値かどうか」という条件に遭遇したので、いろいろ実験したメモです。

やりたいこと

変数a, b, c 全ての数値が異なる場合は「全て異なる値です」と出力し、そうでない場合は「同じ値が含まれています」と出力するプログラムを考えます。

実験1: a!=b!=cと書く

python.py
a = 0
b = 1
c = 0 # a=cのため、同じ値が含まれている
if a != b != c:
    print("全て異なる値です")
else:
    print("同じ値が含まれています")

# 出力 -> "全て異なる値です"

「全て異なる→ a==b==cの逆なのでa≠b≠c」と書いてしまうかもしれませんが、上記の通り、正しく判別することはできません。

Pythonの公式ドキュメントを見てみましょう。

Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).

「 "x < y <= z" は "x < y and y <= z" と等しい」と書いてあります。

つまり、a!=b!=ca!=b and b!=cの判定を行なっているだけでは (≠では推移律が成り立たないので) 、a!= cが成り立っているかどうか は保証されないということです。

(実際に試してみたメモ)
python.py
a, b, c = 0, 0, 1

if a != b != c:
    print("Yes")
else:
    print("No")

# No
# 0 != 0 が偽になるため。

# 一方で、

a, b, c = 0, 1, 0

if a != b != c:
    print("Yes")
else:
    print("No")

# Yes
# 0 != 1 は真であり、かつ、1 != 0 も真であるため、論理式は真になる。

先程のa = 1, b = 0, c = 1を例にすると、$a≠b$ かつ $b≠c$であることは確認しているけれども、「$a≠c$であるかどうか」までは確認していないことになります。

そもそも、$a=b=c$, $a < b ≦ c$ はあっても、 $a≠b≠c$ という式の書き方は、数学や論理式の文脈でグローバルに定義されているものではありません。このような書き方は、たとえ他の言語で運良く意図通りに動いたとしても、可読性の観点から好ましくはないと考えられます。

実験2. not (a==b==c)

python.py
a = 0
b = 1
c = 0
if not (a == b == c):
    print("全て異なる値です")
else:
    print("同じ値が含まれています")

# 出力 -> "全て異なる値です"

論理式を把握されている方からすれば当然と思われるでしょうが、これも「全て異なる」の判定には使えません。
「全て等しい」の否定は「少なくとも1つ異なる」と等しいため、1つだけでも異なるものがあれば真と判定されるためです。

では、どう書けば「全て異なる」を正しく判定できるのでしょうか。

正しい書き方

python.py
if a!=b and b!=c and c!=a:
    #省略

素直に「全て異なる」という条件の中身を展開して、端折らずに書くのが最善と考えられます。

python.py
if a!=b!=c!=a:
    #省略

短く書きたいならば、先述したPythonにおける比較の定義を利用し、 a!=b!=c!=a と書くことで、上と同じ判定を行うこともできます(共有ありがとうございます)。
ちなみに、3個以上の比較でも同様に定義されていることは、公式ドキュメントに記載されています。

Formally, if a, b, c, …, y, z are expressions and op1, op2, …, opN are comparison operators, then a op1 b op2 c ... y opN z is equivalent to a op1 b and b op2 c and ... y opN z, except that each expression is evaluated at most once.

先述したように、数学や論理式として定義されたものではありませんが、可読性はそこまで損なわれないと思います。

ただ、これらの書き方は、4つ以上の要素がある場合には使えません。a!=b and b!=c and c!=d and d!=aだけでは、a!=cb!=dを判定できないためです。

その場合には、以下のような方法が考えられます。

python.py
s = [a,b,c]
if len(set(s)) == len(s):

set型 (集合) を利用して、「set型にlist[a,b,c]を入れ、重複がなければsetの要素数がlistの要素数と等しい」という書き方です(共有ありがとうございます)。
これならば4つ以上でも簡潔に判定できます。

set型についてはこちらに分かりやすく解説されています。

3
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?