((X == a ve y == b) veya (x == b ve y == a)) ifade etmenin daha zarif bir yolu var mı?


108

((x == a and y == b) or (x == b and y == a))Python'da değerlendirmeye çalışıyorum , ama biraz ayrıntılı görünüyor. Daha zarif bir yol var mı?


8
Ne tür nesnelere bağlı x,y, a,bolarak: bunlar ints / float / string, keyfi nesneler mi veya ne? Yerleşik tiplerdeyse ve her ikisini de x,yve a,bsıralı olarak tutmak mümkünse , ikinci daldan kaçınabilirsiniz. Bir küme oluşturmanın, dört öğenin her birinin, x,y, a,btamamen önemsiz olabilecek veya olmayabilecek veya tamamen ne tür nesnelere bağlı olarak performans etkisi olabileceğine neden olacağını unutmayın.
smci

18
Birlikte çalıştığınız insanları ve geliştirdiğiniz projeyi unutmayın. Burada ve orada küçük bir Python kullanıyorum. Birisi buradaki cevaplardan birini kodladıysa, neler olup bittiğini tamamen Google'a gitmek zorunda kalacaktım. Koşulunuz ne olursa olsun hemen hemen okunabilir.
Areks

3
Ben hiçbiri ile rahatsız olmaz. Daha hileli, ama o kadar net değil (IMHO) ve sanırım hepsi daha yavaş olacak.
Barmar

22
Bu klasik bir XYAB problemidir.
Tashus

5
Genel olarak, siparişten bağımsız nesne koleksiyonlarıyla ilgileniyorsanız, set / dicts / etc kullanın. Bu gerçekten bir XY sorunu, daha geniş kod tabanını görmemiz gerekecek. ((x == a and y == b) or (x == b and y == a))Yukky görünebilir kabul ediyorum , ancak 1) amacı şifreli değil, tüm Python olmayan programcılar için kristal berraklığında ve anlaşılır 2) tercümanlar / derleyiciler her zaman iyi işleyecek ve aslında asla performanssız kodla sonuçlanamayacak alternatifler. Yani, 'daha zarif' ciddi dezavantajlara da sahip olabilir.
smci

Yanıtlar:


151

Elemanlar yıkanabilirse, setleri kullanabilirsiniz:

{a, b} == {y, x}

18
@Graham hayır öyle değil, çünkü sağ elinde tam olarak iki madde var. Her ikisi de a ise, b yoktur ve her ikisi de b ise, a yoktur ve her iki durumda da kümeler eşit olamaz.
ocaklar

12
Öte yandan, her iki tarafta üç elementimiz olsaydı ve bunların bire bir eşleşip eşlenemeyeceklerini test etmemiz gerekiyorsa, setler işe yaramazdı. {1, 1, 2} == {1, 2, 2}. Bu noktada, sortedya ihtiyacınız var Counter.
user2357112 Monica

11
Okumak zor görünüyor ("{}" kelimesini "()" olarak okumayın). Yorum yapmak için yeterli - ve sonra amaç kaybolur.
Édouard

9
Python biliyorum ama sadece değerleri karşılaştırmak için iki yeni set oluşturmak bana bir overkill gibi görünüyor ... Sadece bunu yapan bir işlev tanımlayın ve gerektiğinde arayın.
marxin

5
@marxin Bir işlev, 2 basit set yapısından bile daha büyük bir overkill olurdu. Ve 4 argümanla daha az okunabilir.
Gloweye

60

Bence alabileceğiniz en iyi şey onları tuples'e paketlemektir:

if (a, b) == (x, y) or (a, b) == (y, x)

Ya da belki bunu bir set aramasına sarın

if (a, b) in {(x, y), (y, x)}

Birkaç yorumdan bahsedildiği için, bazı zamanlamalar yaptım ve arama başarısız olduğunda tuples ve setler aynı şekilde performans gösteriyor gibi görünüyor:

from timeit import timeit

x = 1
y = 2
a = 3
b = 4

>>> timeit(lambda: (a, b) in {(x, y), (y, x)}, number=int(5e7))
32.8357742

>>> timeit(lambda: (a, b) in ((x, y), (y, x)), number=int(5e7))
31.6169182

Arama başarılı olduğunda tuples aslında daha hızlı olsa da:

x = 1
y = 2
a = 1
b = 2

>>> timeit(lambda: (a, b) in {(x, y), (y, x)}, number=int(5e7))
35.6219458

>>> timeit(lambda: (a, b) in ((x, y), (y, x)), number=int(5e7))
27.753138700000008

Bir set kullanmayı seçtim çünkü bir üyelik araması yapıyorum ve kavramsal olarak bir set bu kullanım senaryosu için bir demetten daha uygun. Belirli bir kullanım durumunda iki yapı arasında önemli bir fark ölçtüyseniz, daha hızlı olanı kullanın. Performansın burada bir faktör olduğunu düşünmüyorum.


12
Tuple yöntemi çok temiz görünüyor. Bir set kullanmanın performans etkisi konusunda endişe duyarım. if (a, b) in ((x, y), (y, x))Yine de yapabilir misin?
Brilliand

18
@Brilliand Performans etkisi konusunda endişeleriniz varsa, Python sizin için bir dil değildir. :-D
Sneftel

İlk yöntemi, iki grup karşılaştırmasını gerçekten çok seviyorum. Ayrıştırmak kolaydır (her seferinde bir fıkra) ve her fıkra çok basittir. Üstelik nispeten verimli olmalı.
Matthieu M.

set@Brilliand'ın tuple çözümüne cevabında çözümü tercih etmek için herhangi bir neden var mı ?
user1717828

Bir küme nesnelerin yıkanabilir olmasını gerektirir, bu nedenle bir demet daha az bağımlılıkla daha genel bir çözüm olacaktır. Muhtemelen genellikle önemli olmasa da, performans, pahalı karma ve eşitlik kontrollerine sahip büyük nesnelerle uğraşırken çok farklı görünebilir.
15'de Dukeling

31

Tuples biraz daha okunabilir hale getiriyor:

(x, y) == (a, b) or (x, y) == (b, a)

Bu bir ipucu verir: dizinin diziye x, yeşit olup olmadığını kontrol edip sıralamayı a, bgöz ardı ediyoruz . Bu sadece eşitlik!

{x, y} == {a, b}

,liste değil bir demet oluşturur. böylece (x, y)ve (a, b)aynı küpe vardır x, yve a, b.
kissgyorgy

Python listtipi anlamında değil, "sıralı elemanlar dizisi" anlamında "liste" demek istedim . Düzenlendi çünkü gerçekten bu kafa karıştırıcıydı.
Thomas

27

Öğeler yıkanamazsa, ancak sipariş karşılaştırmalarını destekliyorsa, deneyebilirsiniz:

sorted((x, y)) == sorted((a, b))

Bu, yıkanabilir öğelerle de çalıştığı için (doğru?), Daha küresel bir çözümdür.
Carl Witthoft

5
@CarlWitthoft: Hayır. Yıkanabilir ancak sıralanamayan türler vardır: complexörneğin.
dan04

26

Bana göre en zarif yol,

(x, y) in ((a, b), (b, a))

Bu, kümeleri kullanmaktan daha iyi bir yoldur, yani {a, b} == {y, x}diğer cevaplarda belirtildiği gibi, değişkenlerin yıkanabilir olup olmadığını düşünmemize gerek yoktur.


Bu, daha önceki cevaptan nasıl farklıdır ?
scohe001

5
@ scohe001 Önceki cevabın bir set kullandığı bir demet kullanır. Bu daha önceki cevap bu çözümü düşündü, ancak bir öneri olarak listelemeyi reddetti.
Brilliand

25

Bunlar sayılarsa kullanabilirsiniz (x+y)==(a+b) and (x*y)==(a*b).

Bunlar karşılaştırılabilir öğelerse kullanabilirsiniz min(x,y)==min(a,b) and max(x,y)==max(a,b).

Ancak ((x == a and y == b) or (x == b and y == a))açık, güvenli ve daha geneldir.


2
Haha, simetrik polinomlar ftw!
Carsten S

2
Bunun taşma hataları riski oluşturduğunu düşünüyorum.
Razvan Socol

3
Bu doğru cevap, özellikle de son cümledir. Basit olun, bu birden fazla yeni yinelenebilir veya böyle bir şey gerektirmemelidir. Kümeleri kullanmak isteyenler için , küme nesnelerinin uygulanmasına bir göz atın ve daha sonra bunu sıkı bir döngüde çalıştırmaya çalıştığınızı hayal edin ...
Z4 katmanı

3
@RazvanSocol OP veri türlerinin ne olduğunu söylemedi ve bu cevap türe bağlı çözümleri nitelendiriyor.
Z4 katmanı

21

İkiden fazla değişkene genelleme olarak kullanabiliriz itertools.permutations. Bunun yerine

(x == a and y == b and z == c) or (x == a and y == c and z == b) or ...

yazabiliriz

(x, y, z) in itertools.permutations([a, b, c])

Ve elbette iki değişkenli versiyon:

(x, y) in itertools.permutations([a, b])

5
Mükemmel cevap. Burada (daha önce jeneratörler ile fazla bir şey yapmayanlar için), bir seferde sadece bir permütasyon oluşturulduğu ve "giriş" kontrolünün durup hemen ardından True'ya döneceği için bunun çok bellek verimli olduğunu belirtmek gerekir. eşleşme bulundu.
robertlayton

2
Ayrıca, bu yöntemin karmaşıklığının O(N*N!); 11 değişken için bu işlemin tamamlanması bir saniye sürebilir. (Daha hızlı bir yöntem yayınladım, ancak hala O(N^2)10k değişken üzerinde bir saniye sürüyor ve almaya başlıyor; Bu, hızlı veya genel olarak yapılabilir (wrt. Hashability / orderability), ancak her ikisi de değil: P)
Aleksi Torhamo

15

Verilerinizi temsil etmek için tuples kullanabilir ve ardından aşağıdakileri içeren set dahil etmeyi kontrol edebilirsiniz:

def test_fun(x, y):
    test_set = {(a, b), (b, a)}

    return (x, y) in test_set

3
Bir astar olarak ve bir liste ile (yıkanamaz öğeler için) yazılmış, bunun en iyi cevap olduğunu düşünürdüm. (tam bir Python acemi olmamasına rağmen).
Édouard

1
@ Édouard Şimdi esas olarak başka bir cevap daha var (sadece liste yerine bir demet ile, bu da yine de daha verimli).
Brilliand

10

En okunabilir çözümü zaten aldınız . Bunu, belki de daha az karakterle ifade etmenin başka yolları da vardır, ancak bunları okumak daha az kolaydır.

Değerlerin gerçekte en iyi bahsinizi temsil ettiğine bağlı olarak , çek ismini konuşan bir isimle sarmaktır . Alternatif olarak veya ek olarak, x, y ve a, b nesnelerini, daha sonra bir sınıf eşitliği kontrol yönteminde veya özel bir özel işlevde karşılaştırmanın mantığı ile karşılaştırabileceğiniz özel yüksek sınıf nesnelerinde modelleyebilirsiniz.


3

OP sadece iki değişkenle ilgiliydi, ancak StackOverflow da aynı soruyu daha sonra arayanlar için olduğundan, genel durumu burada ayrıntılı olarak ele almaya çalışacağım; Önceki bir cevap zaten kullanarak genel bir cevap içerir itertools.permutations(), ancak her biri öğelerle permütasyonlar olduğu için bu yöntem O(N*N!)karşılaştırmaya yol açar . (Bu cevap için ana motivasyon buydu)N!N

İlk olarak, önceki yanıtlardaki yöntemlerden bazılarının burada sunulan yöntem için motivasyon olarak genel durum için nasıl geçerli olduğunu özetleyelim. I kullanarak olacak Aatıfta (x, y)ve Bifade etmek için (a, b)keyfi (fakat eşit) uzunluğunda küpe olabilir,.

set(A) == set(B)hızlıdır, ancak yalnızca değerlerin yıkanabilir olması durumunda çalışır ve gruplardan birinin yinelenen değerler içermediğini garanti edebilirsiniz. (Örn. {1, 1, 2} == {1, 2, 2}, @Daniel Mesejo'nun cevabı altında @ user2357112 tarafından belirtildiği gibi)

Önceki yöntem, kümeler yerine sayıları olan sözlükler kullanarak yinelenen değerlerle çalışmak üzere genişletilebilir: (Bu yine de tüm değerlerin yıkanabilir olması gibi bir sınırlamaya sahiptir, örn. Gibi değiştirilebilir değerler listçalışmaz)

def counts(items):
    d = {}
    for item in items:
        d[item] = d.get(item, 0) + 1
    return d

counts(A) == counts(B)

sorted(A) == sorted(B)yıkanabilir değerler gerektirmez, ancak biraz daha yavaştır ve bunun yerine düzenlenebilir değerler gerektirir. (Yani, örneğin complexçalışmaz)

A in itertools.permutations(B)yıkanabilir veya düzenlenebilir değerler gerektirmez, ancak daha önce de belirtildiği gibi, O(N*N!)karmaşıklığı vardır, bu nedenle sadece 11 öğeyle bile bitirmek bir saniyeyi alabilir.

Peki, genel olmanın bir yolu var, ama çok daha hızlı mı? Neden evet, "el ile" her öğenin aynı miktarda olup olmadığını kontrol ederek: (Bunun karmaşıklığı, bu O(N^2)büyük girişler için de iyi değil; Makinemde 10k öğe bir saniyeyi devralabilir - ancak 10 öğe gibi daha küçük girdiler, bu diğerleri kadar hızlıdır)

def unordered_eq(A, B):
    for a in A:
        if A.count(a) != B.count(a):
            return False
    return True

En iyi performansı elde etmek için, dictilk önce sorted-based yöntemini denemek, shahable değerleri nedeniyle başarısız olursa -based countyöntemine geri dönmek ve nihayetinde dayanılmaz değerler nedeniyle başarısız olursa -based yöntemine geri dönmek isteyebilirsiniz.

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.