値に対して複数の変数をテストする方法は?


645

複数の変数を整数と比較して3文字の文字列を出力する関数を作成しようとしています。これをPythonに変換する方法があるかどうか疑問に思っていました。だから、言って:

x = 0
y = 1
z = 3
mylist = []

if x or y or z == 0 :
    mylist.append("c")
if x or y or z == 1 :
    mylist.append("d")
if x or y or z == 2 :
    mylist.append("e")
if x or y or z == 3 : 
    mylist.append("f")

これは次のリストを返します:

["c", "d", "f"]

このようなことは可能ですか?


5
使用1(タプル)で

2
ステートメントのリストを任意/すべての方法で評価する場合は、any/ all関数を使用できます。例:all([1, 2, 3, 4, False])false all([True, 1, 2, 3])を返す、true any([False, 0, 0, False])を返す、false any([False, 0, True, False])を返す、trueを返す
eddd

4
この質問は非常に一般的な重複ターゲットですが、その目的には最適ではないと思います。ほとんどの人はのようなことを試みますがif x == 0 or 1:、これはもちろんに似てif x or y == 0:いますが、それでも初心者には少し混乱するかもしれません。「なぜ私のx == 0 or 1仕事ではないのか」という膨大な量を考えると 質問、私はむしろこれらの質問のための私たちの正規の重複ターゲットとしてこの質問を使用します。
Aran-Fey

1
以下のような「falsey」の値を比較する際に細心の注意を払ってください00.0またはFalse。「正しい」答えを与える間違ったコードを簡単に書くことができます。
smci

回答:


850

ブール式の仕組みを誤解している。それらは英文のようには機能せず、ここですべての名前の同じ比較について話していると思います。あなたは探している:

if x == 1 or y == 1 or z == 1:

xそして、y(そうでない場合は、自分で評価されFalseている場合0Trueそうでありません)。

あなたはタプルに対する包含テストを使用してそれを短くすることができます:

if 1 in (x, y, z):

またはより良い:

if 1 in {x, y, z}:

asetを使用て、一定コストのメンバーシップテストを利用します(in左側のオペランドが何であっても一定の時間がかかります)。

を使用するとor、Pythonは演算子の両側を別々の式として認識ます。式x or y == 1は最初にのブールテストとして扱われx、それがFalseの場合、式y == 1がテストされます。

これは、演算子の優先順位によるものです。orオペレータは、より低い優先順位有する==後者が評価されるので、テストを最初

ただし、これが当てはまらず、式x or y or z == 1が実際に(x or y or z) == 1代わりに解釈されたとしても、期待どおりに動作しません。

x or y or zは、「真」である最初の引数、たとえばFalse、数値0や空などに評価されます(ブールコンテキストでPythonがfalseと見なすものの詳細については、ブール式を参照してください)。

したがって、値の場合x = 2; y = 1; z = 0x or y or zはに解決され2ます。これは、引数の最初の真のような値だからです。その後2 == 1だろうFalseにもかかわらず、y == 1だろうTrue

同じことが逆にも当てはまります。単一の変数に対して複数の値をテストします。x == 1 or 2 or 3同じ理由で失敗します。x == 1 or x == 2 or x == 3またはを使用しx in {1, 2, 3}ます。


116
私はそのsetバージョンに行くのはそれほど速くはないでしょう。タプルの作成と反復は非常に安価です。少なくとも私のマシンでは、タプルのサイズが約4〜8要素である限り、タプルはセットよりも高速です。それ以上スキャンする必要がある場合は、セットを使用しますが、2〜4つの可能性のあるアイテムを探している場合は、タプルの方が高速です。最も可能性の高いケースをタプルの最初に配置できる場合、勝利はさらに大きくなります:(私のテスト:timeit.timeit('0 in {seq}'.format(seq=tuple(range(9, -1, -1))))
SingleNegationElimination 2013年

57
@dequestarmappartialsetattr:Python 3.3以降では、セットは定数として保存され、作成時間を完全にバイパスして作成時間を排除します。タプル、メモリチャーンを回避するためにPythonがそれらのバンドルをキャッシュするため、安価に作成でき、ここでのセットとの最大の違いになります。
Martijn Pieters

13
@dequestarmappartialsetattr:メンバーシップテストだけの時間を計測すると、整数セットとタプルは理想的なシナリオでは同等に高速です。最初の要素に一致します。その後、タプルはセットに負けます。
Martijn Pieters

17
@MartijnPieters:setこのテストにリテラル表記を使用することは、setリテラルの内容もリテラルである場合を除いて、節約ではありませんか?if 1 in {x, y, z}:キャッシュできないset、のでxyおよびz構築するため変更される可能性があり、そのいずれかのソリューションのニーズtuplesetスクラッチからの、そして私は、会員のためのチェックが大きいことにより、殺到するだろうというとき、あなたが得る可能性があります、ルックアップどんな貯蓄疑いset作成時間。
ShadowRanger

9
@ShadowRanger:はい、のぞき穴の最適化(in [...]またはin {...})は、リストまたはセットの内容も不変のリテラルである場合にのみ機能します。
Martijn Pieters

96

あなたの問題は、次のような辞書構造でより簡単に対処できます。

x = 0
y = 1
z = 3
d = {0: 'c', 1:'d', 2:'e', 3:'f'}
mylist = [d[k] for k in [x, y, z]]

21
または、d = "cdef"それが次の原因となる場合MyList = ["cdef"[k] for k in [x, y, z]]
アラガエル2013年

9
またはmap(lambda i: 'cdef'[i], [x, y, z])
dansalmo 2014年

3
@MJM出力順序はディクテーションではなく、リストの順序で決まります[x, y, z]
dansalmo

1
私がまだ十分に慣れていないリストの理解を除けば、ほとんどの人が同じ反射神経を持っていました。その辞書を構築してください!
LoneWanderer

66

Martijn Pietersが述べたように、正しい、最も速い形式は次のとおりです。

if 1 in {x, y, z}:

if文の彼のアドバイスを使用して、あなたは今、Pythonが、前者はなかったかどうかをそれぞれの文を読みますので、別々のだろうTrueFalse。といった:

if 0 in {x, y, z}:
    mylist.append("c")
if 1 in {x, y, z}:
    mylist.append("d")
if 2 in {x, y, z}:
    mylist.append("e")
...

この意志の仕事が、あればあなたは(私はそこに何をしたかを参照)の辞書を使用して慣れている、あなただけのために、ループ使用して、その後、最初の辞書はあなたがしたい文字に数字をマッピングすることによって、このアップをきれいにすることができます:

num_to_letters = {0: "c", 1: "d", 2: "e", 3: "f"}
for number in num_to_letters:
    if number in {x, y, z}:
        mylist.append(num_to_letters[number])

45

直接書く方法x or y or z == 0

if any(map((lambda value: value == 0), (x,y,z))):
    pass # write your logic.

しかし、私は思いません、あなたはそれが好きです。:)そして、この方法は醜いです。

もう1つの方法(より良い)は次のとおりです。

0 in (x, y, z)

ところで多くのifsはこのようなものとして書くことができます

my_cases = {
    0: Mylist.append("c"),
    1: Mylist.append("d")
    # ..
}

for key in my_cases:
    if key in (x,y,z):
        my_cases[key]()
        break

8
dictキーではなくの例で.appendNone、is の戻り値が原因でエラーが発生し、呼び出しNoneによってが返されますAttributeError。ただし、一般的にはこの方法に同意します。
SethMMorton 2014

2
キーの代わりにdictが間違っている場合、 "for..loop"の部分をコメントアウトしても、辞書が初期化されるとMylist = ['c'、 'd']になります
Mahmoud Elshahat

1
最初の例でfiltermap、lambdaがtrueと評価されるインスタンスのみが返されるため、よりも優れています
Alex

1
理解はラムダのマップよりもはるかに単純です:any(v == 0 for v in (x, y, z))
wjandrea

35

非常に怠惰な場合は、配列内に値を入れることができます。といった

list = []
list.append(x)
list.append(y)
list.append(z)
nums = [add numbers here]
letters = [add corresponding letters here]
for index in range(len(nums)):
    for obj in list:
        if obj == num[index]:
            MyList.append(letters[index])
            break

数字や文字を辞書に入れて実行することもできますが、これはおそらく単純なifステートメントよりもはるかに複雑です。それはあなたが余分な怠惰にしようとするために得るものです:)

もう一つ、あなたの

if x or y or z == 0:

コンパイルされますが、希望どおりにはなりません。変数を単純にifステートメントに配置する場合(例)

if b

プログラムは変数がnullでないかどうかをチェックします。上記のステートメントを書く別の方法(これはより理にかなっています)です。

if bool(b)

Boolはpythonの組み込み関数であり、基本的にブール文を検証するコマンドを実行します(これが何であるかわからない場合は、現在if文で作成しようとしていることです)。

私が見つけた別の怠惰な方法は:

if any([x==0, y==0, z==0])

3
-1ここには悪い習慣がたくさんあります。listPythonの組み込みです。代わりに、xyzたとえば別の名前を使用してください。リストを作成できるのに、なぜ4つのステップでリストを作成するのxyz = [x, y, z]ですか?並列リストを使用せず、代わりにdictを使用してください。全体として、このソリューションは、ThatGuyRussellのソリューションよりもはるかに複雑です。最後の部分についても、理解を深めany(v == 0 for v in (x, y, z))ませんか?また、配列はPythonでは別のものです。
wjandrea

32

値が変数のセット内に含まれているかどうかを確認するには、組み込みモジュールitertoolsとを使用できます operator

例えば:

輸入:

from itertools import repeat
from operator import contains

変数を宣言します。

x = 0
y = 1
z = 3

値のマッピングを作成します(確認したい順序で):

check_values = (0, 1, 3)

itertools変数の繰り返しを許可するために使用します。

check_vars = repeat((x, y, z))

最後に、map関数を使用してイテレータを作成します。

checker = map(contains, check_vars, check_values)

次に、値を(元の順序で)チェックする場合は、次を使用しますnext()

if next(checker)  # Checks for 0
    # Do something
    pass
elif next(checker)  # Checks for 1
    # Do something
    pass

等...

これには、 lambda x: x in (variables)operatorは組み込みモジュールでありlambda、カスタムインプレース関数を作成する必要があるを使用するよりも高速で効率的でためます。

リストにゼロ以外の(またはFalse)値があるかどうかを確認する別のオプション:

not (x and y and z)

同等:

not all((x, y, z))

2
これはOPの質問には答えません。提供されている例の最初のケースのみをカバーしています。
ワラサー2014年

31

Setは、変数を順序付けるので、ここでの良いアプローチです。パラメータの順序{z,y,x}{0,1,3}何でもかまいません。

>>> ["cdef"[i] for i in {z,x,y}]
['c', 'd', 'f']

このように、全体の解はO(n)です。


5
あなたのコードが何を達成するか、そしてそれがどのようにそれを実行するかの説明を追加する必要があります。コードのみを使用した短い回答はお勧めしません
Raniz

31

ここで提供される優れた回答はすべて、元のポスターの特定の要件に集中し、if 1 in {x,y,z}Martijn Pietersによって提案されたソリューションに集中します。
彼らが無視しているのは、質問の幅広い意味です:
1つの変数を複数の値に対してテストするにはどうすればよいですか?
提供されたソリューションは、たとえば文字列を使用している場合、部分的なヒットに対しては機能しません:
文字列「Wild」が複数の値にあるかどうかをテストします

>>> x = "Wild things"
>>> y = "throttle it back"
>>> z = "in the beginning"
>>> if "Wild" in {x, y, z}: print (True)
... 

または

>>> x = "Wild things"
>>> y = "throttle it back"
>>> z = "in the beginning"
>>> if "Wild" in [x, y, z]: print (True)
... 

このシナリオでは、文字列に変換するのが最も簡単です

>>> [x, y, z]
['Wild things', 'throttle it back', 'in the beginning']
>>> {x, y, z}
{'in the beginning', 'throttle it back', 'Wild things'}
>>> 

>>> if "Wild" in str([x, y, z]): print (True)
... 
True
>>> if "Wild" in str({x, y, z}): print (True)
... 
True

ただし、で述べたように@codeforester、この方法では次のように単語の境界が失われることに注意してください。

>>> x=['Wild things', 'throttle it back', 'in the beginning']
>>> if "rot" in str(x): print(True)
... 
True

3つの文字rotはリストに組み合わせて存在しますが、個別の単語としては存在しません。「rot」のテストは失敗しますが、リスト項目の1つが「地獄で腐敗」した場合、それも失敗します。
つまり、この方法を使用する場合は検索条件に注意し、この制限があることに注意してください。


30

これでうまく処理できると思います。

my_dict = {0: "c", 1: "d", 2: "e", 3: "f"}

def validate(x, y, z):
    for ele in [x, y, z]:
        if ele in my_dict.keys():
            return my_dict[ele]

出力:

print validate(0, 8, 9)
c
print validate(9, 8, 9)
None
print validate(9, 8, 2)
e

30

ifを使用する場合は、以下のelseステートメントが別の解決策です。

myList = []
aList = [0, 1, 3]

for l in aList:
    if l==0: myList.append('c')
    elif l==1: myList.append('d')
    elif l==2: myList.append('e')
    elif l==3: myList.append('f')

print(myList)


26

このコードは役立つかもしれません

L ={x, y, z}
T= ((0,"c"),(1,"d"),(2,"e"),(3,"f"),)
List2=[]
for t in T :
if t[0] in L :
    List2.append(t[1])
    break;

12

以下に示す方法を試すことができます。この方法では、入力する変数の数を自由に指定/入力できます。

mydict = {0:"c", 1:"d", 2:"e", 3:"f"}
mylist= []

num_var = int(raw_input("How many variables? ")) #Enter 3 when asked for input.

for i in range(num_var): 
    ''' Enter 0 as first input, 1 as second input and 3 as third input.'''
    globals()['var'+str('i').zfill(3)] = int(raw_input("Enter an integer between 0 and 3 "))
    mylist += mydict[globals()['var'+str('i').zfill(3)]]

print mylist
>>> ['c', 'd', 'f']

10

1行のソリューション:

mylist = [{0: 'c', 1: 'd', 2: 'e', 3: 'f'}[i] for i in [0, 1, 2, 3] if i in (x, y, z)]

または:

mylist = ['cdef'[i] for i in range(4) if i in (x, y, z)]

9

たぶん、出力ビットを設定するための直接的な公式が必要です。

x=0 or y=0 or z=0   is equivalent to x*y*z = 0

x=1 or y=1 or z=1   is equivalent to (x-1)*(y-1)*(z-1)=0

x=2 or y=2 or z=2   is equivalent to (x-2)*(y-2)*(z-2)=0

ビットにマッピングしましょう: 'c':1 'd':0xb10 'e':0xb100 'f':0xb1000

iscの関係(is 'c'):

if xyz=0 then isc=1 else isc=0

https://youtu.be/KAdKCgBGK0k?list=PLnI9xbPdZUAmUL8htSl6vToPQRRN3hhFp&t=315の場合は数学を使用

[c]: (xyz=0 and isc=1) or (((xyz=0 and isc=1) or (isc=0)) and (isc=0))

[d]: ((x-1)(y-1)(z-1)=0 and isc=2) or (((xyz=0 and isd=2) or (isc=0)) and (isc=0))

...

次のロジックでこれらの数式を接続します。

  • 論理 andは方程式の二乗の合計です
  • 論理orは方程式の積です

そして、あなたは合計方程式の合計を持っているでしょう、そしてあなたは合計の合計式を持っています

次に、sum&1はc、sum&2はd、sum&4はe、sum&5はf

この後、文字列要素のインデックスが準備ができた文字列に対応する定義済み配列を形成できます。

array[sum] あなたに文字列を与えます。


7

それは簡単に行うことができます

for value in [var1,var2,var3]:
     li.append("targetValue")

6

Pythonで疑似コードを表す最もニーモニックな方法は次のとおりです。

x = 0
y = 1
z = 3
mylist = []

if any(v == 0 for v in (x, y, z)):
    mylist.append("c")
if any(v == 1 for v in (x, y, z)):
    mylist.append("d")
if any(v == 2 for v in (x, y, z)):
    mylist.append("e")
if any(v == 3 for v in (x, y, z)):
    mylist.append("f")

1
このアプローチは、任意の比較を許可するため(例:)、 `if 2 in(x、y、z):mylist.append( 'e')`よりも普遍的ですif any(v >= 42 for v in (x, y, z)):。そして、すべての3つの方法のパフォーマンスは(2 in {x,y,z}2 in (x,y,z)any(_v == 2 for _v in (x,y,z)))CPython3.6でほぼ同じであると思われる(参照要旨を
imposeren

5

1つの値で複数の変数をテストするには: if 1 in {a,b,c}:

1つの変数で複数の値をテストするには: if a in {1, 2, 3}:


4

何らかのシーザー暗号を作成しているようです。

より一般的なアプローチは次のとおりです。

input_values = (0, 1, 3)
origo = ord('c')
[chr(val + origo) for val in inputs]

出力

['c', 'd', 'f']

それがコードの望ましい副作用かどうかはわかりませんが、出力の順序は常にソートされます。

これが必要な場合は、最終行を次のように変更できます。

sorted([chr(val + origo) for val in inputs])

2

辞書を使用できます:

x = 0
y = 1
z = 3
list=[]
dict = {0: 'c', 1: 'd', 2: 'e', 3: 'f'}
if x in dict:
    list.append(dict[x])
else:
    pass

if y in dict:
    list.append(dict[y])
else:
    pass
if z in dict:
    list.append(dict[z])
else:
    pass

print list

1
これは、これを一度追加すると同じです。セットする?
セルゲイ、

2

辞書なしで、この解決策を試してください:

x, y, z = 0, 1, 3    
offset = ord('c')
[chr(i + offset) for i in (x,y,z)]

そして与える:

['c', 'd', 'f']

0

これはあなたを助けます。

def test_fun(val):
    x = 0
    y = 1
    z = 2
    myList = []
    if val in (x, y, z) and val == 0:
        myList.append("C")
    if val in (x, y, z) and val == 1:
        myList.append("D")
    if val in (x, y, z) and val == 2:
        myList.append("E")

test_fun(2);

0

あなたはこれを団結させることができます

x = 0
y = 1
z = 3

1つの変数で。

In [1]: xyz = (0,1,3,) 
In [2]: mylist = []

次のように条件を変更します。

In [3]: if 0 in xyz: 
    ...:     mylist.append("c") 
    ...: if 1 in xyz: 
    ...:     mylist.append("d") 
    ...: if 2 in xyz: 
    ...:     mylist.append("e") 
    ...: if 3 in xyz:  
    ...:     mylist.append("f") 

出力:

In [21]: mylist                                                                                
Out[21]: ['c', 'd', 'f']

0

問題

複数の値をテストするためのパターンが

>>> 2 in {1, 2, 3}
True
>>> 5 in {1, 2, 3}
False

非常に読みやすく、多くの状況で機能しますが、1つの落とし穴があります。

>>> 0 in {True, False}
True

しかし、

>>> (0 is True) or (0 is False)
False

解決

前の表現の一般化の1つは、ytpillaiからの回答に基づいています。

>>> any([0 is True, 0 is False])
False

これは次のように書くことができます

>>> any(0 is item for item in (True, False))
False

この式は正しい結果を返しますが、最初の式:-(

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.