Birden çok değişkeni bir değere karşı nasıl test edebilirim?


644

Bir tamsayı için birden çok değişken karşılaştıracak ve üç harfli bir dize çıktısı olacak bir işlev yapmaya çalışıyorum. Bunu Python'a çevirmenin bir yolu olup olmadığını merak ediyordum. Yani söyle:

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")

bir liste döndürür:

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

Böyle bir şey mümkün mü?


5
kullanımı 1(tuple)

2
İfadelerin bir listesini herhangi bir / her şekilde değerlendirmek istediğinizde any/ allfonksiyonlarını kullanabilirsiniz . Örneğin: all([1, 2, 3, 4, False])False all([True, 1, 2, 3])döndürecek True any([False, 0, 0, False])döndürecek False any([False, 0, True, False])döndürecek True
eddd

4
Bu soru çok popüler bir yinelenen hedef, ancak bence bu amaç için yetersiz. Çoğu insan buna benzer bir şey yapmaya çalışır , ancak if x == 0 or 1:elbette buna benzer if x or y == 0:, ancak yeni başlayanlar için biraz kafa karıştırıcı olabilir. Hacmi göz önüne alındığında "Neden benim değil x == 0 or 1çalışma?" sorular, bu soruyu bu sorular için standart yinelenen hedefimiz olarak kullanmayı tercih ederim .
Aran-Fey

1
Gibi "Falsey" değerlere karşılaştırırken ekstra özen gösterin 0, 0.0ya da False. Kolayca "doğru" cevap veren yanlış kod yazabilirsiniz.
smci

Yanıtlar:


850

Boole ifadelerinin nasıl çalıştığını yanlış anlarsınız; İngilizce bir cümle gibi çalışmıyorlar ve sanırım burada tüm isimler için aynı karşılaştırmadan bahsediyorsunuz. Şunu arıyorsunuz:

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

xve yaksi (kendi başlarına değerlendirilir Falseeğer 0, Trueaksi).

Bir tupa karşı çevreleme testi kullanarak kısaltmayı yapabilirsiniz :

if 1 in (x, y, z):

veya daha iyisi:

if 1 in {x, y, z}:

kullanarak birset sabit maliyetli üyelik testinin yararlanmak için ( inzaman sabit bir miktar ne olursa olsun sol alır işlenendir).

Kullandığınızda or, python operatörün her iki yüzünü ayrı ifadeler olarak görür . İfade x or y == 1önce bir boole testi olarak kabul edilir x, daha sonra False ise ifade y == 1test edilir.

Bu operatörün önceliğinden kaynaklanmaktadır . orOperatör daha düşük önceliğe sahip ==ikinci değerlendirilir, böylece test önce .

Ancak, durum böyle olmasa ve ifade x or y or z == 1aslında (x or y or z) == 1bunun yerine yorumlanmış olsa bile, bu yine de yapmasını beklediğiniz şeyi yapmazdı.

x or y or z"doğruluk" olan ilk argümanı değerlendirir, örneğin Falsesayısal 0 veya boş değildir ( Python'un bir mantıksal bağlamda neyi yanlış gördüğü hakkında ayrıntılar için mantıksal ifadelere bakın ).

Değerler için x = 2; y = 1; z = 0, x or y or zçözülür 2, çünkü bu, bağımsız değişkenlerdeki ilk gerçek benzeri değerdir. O 2 == 1zaman False, olsa da y == 1olurdu True.

Aynı şey tersi için de geçerlidir; tek bir değişkene karşı birden fazla değerin test edilmesi; x == 1 or 2 or 3aynı sebeplerden dolayı başarısız olur. x == 1 or x == 2 or x == 3Veya tuşunu kullanın x in {1, 2, 3}.


116
Sürüme gitmek için o kadar hızlı olmazdım set. Tuplelar oluşturmak ve tekrarlamak çok ucuzdur. Makinemde en azından, tuple boyutu yaklaşık 4-8 ​​eleman olduğu sürece tuples setlerden daha hızlıdır. Bundan daha fazlasını taramanız gerekiyorsa, bir set kullanın, ancak 2-4 olasılıktan bir öğe arıyorsanız, bir demet hala daha hızlıdır! Eğer demet içinde ilk olması en muhtemel durum için ayarlayabiliriz, kazan daha da büyüktür: (benim test: timeit.timeit('0 in {seq}'.format(seq=tuple(range(9, -1, -1)))))
SingleNegationElimination

57
@dequestarmappartialsetattr: Python 3.3 ve sonraki sürümlerde, küme, oluşturma süresini tamamen atlayarak, oluşturma süresini ortadan kaldırarak sabit olarak saklanır. Python bellek karmaşasından kaçınmak için bir paket önbelleğe aldığından Tuples'ı oluşturmak ucuz olabilir , bu da buradaki setlerle en büyük farkı yaratır.
Martijn Pieters

13
@dequestarmappartialsetattr: Sadece üyelik testine zaman ayırırsanız , tamsayı kümeleri ve tuples için ideal senaryo için eşit derecede hızlıdır; ilk öğe eşleştirme. Bundan sonra tuples setlere düşer.
Martijn Pieters

17
@MartijnPieters: setLiteral içerik setde değişmez olmadıkça, bu test için değişmez gösterimi kullanmak bir tasarruf değildir , değil mi? if 1 in {x, y, z}:önbelleğe olamaz set, çünkü x, yve zya çözüm ihtiyaçları inşa etmek, böylece değiştirebilir tupleveya setsıfırdan ve ben üyelik kontrol büyüktür tarafından gömülmek zaman alabilirsiniz tasarruf arama neyse şüpheli setoluşturma zaman.
ShadowRanger

9
@ShadowRanger: evet, gözetleme deliği optimizasyonu ( in [...]veya bunun için olsun in {...}) yalnızca liste veya kümenin içeriği değişmez değişmez değerlerdeyse çalışır.
Martijn Pieters

96

Sorununuz aşağıdaki gibi bir sözlük yapısıyla daha kolay çözülebilir:

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
Ya da hatta d = "cdef"yol açarMyList = ["cdef"[k] for k in [x, y, z]]
aragaer

9
veyamap(lambda i: 'cdef'[i], [x, y, z])
dansalmo

3
@MJM çıktı sırası dikte tarafından belirlenmez, listenin sırasına göre belirlenir[x, y, z]
dansalmo

1
Henüz tam olarak alışkın olmadığım liste kavrayışının yanı sıra, çoğumuz da aynı reflekslere sahiptik: o dikeni inşa et!
LoneWanderer

66

Martijn Pieters tarafından belirtildiği gibi, doğru ve en hızlı biçim:

if 1 in {x, y, z}:

Onun tavsiyesini kullanarak artık Python'un her bir ifadeyi eski olsun Trueya da olmasın okuyacak ayrı if-ifadeleri olacaktı False. Gibi:

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")
...

Bu irade çalışır, ancak eğer sen sözlükleri kullanarak rahat sonra sadece kullanarak, istediğiniz harflere bir ilk sözlüğü haritalayan numaralarını yaparak bu temizleyebilir, (orada ne yaptığını bakınız) bir for döngüsü:

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

Yazma doğrudan yolu x or y or z == 0olduğunu

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

Ama sanmıyorum, hoşuna gidiyor. :) Ve bu şekilde çirkin.

Diğer yol (daha iyi):

0 in (x, y, z)

BTW birçok ifs böyle bir şey olarak yazılabilir

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
dictBir anahtar yerine örneğinizde , dönüş değeri ' .appendolduğundan Noneve çağırmak bir Noneverir AttributeError. Genel olarak bu yönteme katılıyorum.
SethMMorton

2
bir anahtar yerine dikte yanlış ise, "for..loop" bölümünü yorumlasanız bile sözlük başlatıldığında Mylist = ['c', 'd'] elde edersiniz
Mahmoud Elshahat

1
İlk örneğinizde , filtermap
Alex

1
Bir anlama bir lambda haritasından çok daha basittir:any(v == 0 for v in (x, y, z))
wjandrea

35

Çok tembelseniz, değerleri bir dizinin içine koyabilirsiniz. Gibi

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

Ayrıca, sayıları ve harfleri bir sözlüğe koyabilir ve yapabilirsiniz, ancak bu muhtemelen ifadelerden çok daha karmaşıktır. Ekstra tembel olmaya çalıştığınız şey budur :)

Bir şey daha var,

if x or y or z == 0:

derler, ancak istediğiniz şekilde değil. Bir if ifadesine basit bir değişken koyduğunuzda (örnek)

if b

program değişkenin boş olup olmadığını kontrol eder. Yukarıdaki ifadeyi yazmanın başka bir yolu da (daha anlamlı)

if bool(b)

Bool, temel olarak bir boolean deyimini doğrulama komutunu yapan python'da yerleşik bir işlevdir (Bunun ne olduğunu bilmiyorsanız, şu anda if deyiminizde yapmaya çalıştığınız şeydir :))

Bulduğum başka bir tembel yol:

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

3
-1 Burada çok fazla kötü uygulama var. listbir Python yerleşikidir; bunun yerine xyzörneğin başka bir ad kullanın . Listeyi yapabildiğinizde neden dört adımda liste oluşturuyorsunuz xyz = [x, y, z]? Paralel listeler kullanmayın, bunun yerine bir dikte kullanın. Sonuçta, bu çözüm ThatGuyRussell'den çok daha kıvrımlıdır . Ayrıca son kısım için, neden bir kavrayış yapmıyorsunuz, yani any(v == 0 for v in (x, y, z))? Ayrıca diziler Python'da başka bir şeydir.
wjandrea

32

Bir değerin bir değişken kümesi içinde olup olmadığını kontrol etmek için dahili modülleri itertoolsve kullanabilirsiniz operator.

Örneğin:

İthalat:

from itertools import repeat
from operator import contains

Değişkenleri bildir:

x = 0
y = 1
z = 3

Değerlerin eşleştirilmesini oluşturun (kontrol etmek istediğiniz sırayla):

check_values = (0, 1, 3)

itertoolsDeğişkenlerin tekrarlanmasına izin vermek için kullanın :

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

Son olarak, mapyineleyici oluşturmak için işlevi kullanın:

checker = map(contains, check_vars, check_values)

Ardından, değerleri (orijinal sırada) kontrol ederken next()şunları kullanın :

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

vb...

Bunun bir avantajı vardır, lambda x: x in (variables)çünkü operatordahili bir modüldür ve lambdaözel bir yerinde işlev oluşturmak zorunda olandan daha hızlı ve daha verimlidir .

Listede sıfırdan farklı (veya Yanlış) bir değer olup olmadığını kontrol etmek için başka bir seçenek:

not (x and y and z)

Eşdeğer:

not all((x, y, z))

2
Bu OP'nin sorusuna cevap vermiyor. Sadece verilen örnekteki ilk durumu kapsar.
wallacer

31

Set burada iyi bir yaklaşımdır, çünkü değişkenleri sıralar, burada hedefiniz ne gibi görünür. {z,y,x}olduğu {0,1,3}parametrelerin ne düzen.

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

Bu şekilde, bütün çözelti O (n) olur.


5
Kodunuzun neyi başardığına ve kodun nasıl çalıştığına dair bir açıklama eklemelisiniz. Sadece kod kullanarak kısa cevaplar önerilmemektedir
Raniz

31

Burada verilen tüm mükemmel cevaplar, orijinal posterin özel gereksinimlerine ve if 1 in {x,y,z}Martijn Pieters tarafından ortaya konulan çözüme odaklanmaktadır .
Gözardı ettikleri şey sorunun daha geniş bir sonucudur:
Bir değişkeni birden çok değere karşı nasıl test edebilirim?
Dizeler kullanılıyorsa, sağlanan çözüm kısmi isabetlerde çalışmaz:
"Wild" dizesinin birden çok değerde olup olmadığını test edin

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

veya

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

bu senaryo için bir dizeye dönüştürmek en kolay

>>> [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

Bununla birlikte, belirtildiği gibi @codeforester, kelime sınırlarının bu yöntemle kaybolduğu belirtilmelidir:

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

3 harf rotlistede bir arada bulunur, ancak tek bir sözcük olarak bulunmaz. "Çürüme" için test başarısız olur, ancak liste öğelerinden biri "cehennemde çürür" olsaydı, bu da başarısız olur.
Sonuç olarak, bu yöntemi kullanıyorsanız arama kriterlerinize dikkat edin ve bu sınırlamaya sahip olduğunu unutmayın.


30

Bunun daha iyi işleyeceğini düşünüyorum:

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]

Çıktı:

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

30

Eğer if kullanmak istiyorsanız, aşağıdaki ifadeler başka bir çözümdür:

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
d = {0:'c', 1:'d', 2:'e', 3: 'f'}
x, y, z = (0, 1, 3)
print [v for (k,v) in d.items() if x==k or y==k or z==k]

26

Bu kod yardımcı olabilir

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

Aşağıda gösterilen yöntemi deneyebilirsiniz. Bu yöntemde, girmek istediğiniz değişken sayısını belirleme / girme özgürlüğüne sahip olacaksınız.

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

Tek hat çözümü:

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

Veya:

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

9

Belki çıktı bitleri için doğrudan formüle ihtiyacınız vardır.

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

Şimdi bitlerle eşleştirelim: 'c':1 'd':0xb10 'e':0xb100 'f':0xb1000

İsc ilişkisi ('c' dir):

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

Formül https://youtu.be/KAdKCgBGK0k?list=PLnI9xbPdZUAmUL8htSl6vToPQRRN3hhFp&t=315 ise matematik kullanın

[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))

...

Bu formülleri aşağıdaki mantığı kullanarak bağlayın:

  • mantık anddenklemlerin karelerinin toplamıdır
  • mantık ordenklemlerin çarpımıdır

ve toplam denklem ekspres toplamına sahip olacaksınız ve toplam toplam formülüne sahip olacaksınız.

o zaman toplam & 1 c, toplam & 2 d, toplam & 4 e, toplam & 5 f

Bundan sonra, dize elemanları dizininin hazır dizeye karşılık geleceği önceden tanımlanmış bir dizi oluşturabilirsiniz.

array[sum] size dizeyi verir.


7

Kolayca yapılabilir

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

6

Python'da sahte kodunuzu temsil etmenin en anımsatıcı yolu:

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
Bu yaklaşım, (x, y, z): mylist.append ('e') `deki 2'den daha evrenseldir çünkü keyfi karşılaştırmaya izin verir (örn. if any(v >= 42 for v in (x, y, z)):). Ve tüm 3 yöntemlerin performansı ( 2 in {x,y,z}, 2 in (x,y,z), any(_v == 2 for _v in (x,y,z))) CPython3.6 neredeyse aynı gibi görünüyor (bkz Özü )
imposeren

5

Tek bir değerle birden çok değişkeni test etmek için: if 1 in {a,b,c}:

Tek bir değişkenle birden çok değeri test etmek için: if a in {1, 2, 3}:


4

Görünüşe göre bir tür Sezar şifresi inşa ediyorsun.

Çok daha genel bir yaklaşım şudur:

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

çıktılar

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

Kodunuzun istenen bir yan etkisi olup olmadığından emin değilsiniz, ancak çıktınızın sırası her zaman sıralanır.

İstediğiniz buysa, son satır şu şekilde değiştirilebilir:

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

2

Sözlüğü kullanabilirsiniz:

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
Bu, bir defadan daha fazla eklenebilir. Ayarlamak?
Sergei

2

Diksiyon olmadan bu çözümü deneyin:

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

ve verir:

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

0

Bu sana yardım edecek.

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

Bunu birleştirebilirsin

x = 0
y = 1
z = 3

tek bir değişkende.

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

Koşullarımızı şu şekilde değiştirin:

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") 

Çıktı:

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

0

Sorun

Birden çok değeri test etme düzeni

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

çok okunabilir ve birçok durumda çalışıyor, bir tuzak var:

>>> 0 in {True, False}
True

Ama biz istiyoruz

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

Çözüm

Önceki ifadenin genelleştirilmesi, ytpillai'nin cevabına dayanmaktadır :

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

hangi olarak yazılabilir

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

Bu ifade doğru sonucu döndürürken, ilk ifade kadar okunabilir değildir :-(

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.