Có cách nào thanh lịch hơn để thể hiện ((x == a và y == b) hoặc (x == b và y == a))?


108

Tôi đang cố gắng đánh giá ((x == a and y == b) or (x == b and y == a))bằng Python, nhưng có vẻ hơi dài dòng. Có cách nào thanh lịch hơn?


8
Phụ thuộc vào loại đối tượng x,y, a,blà: chúng là ints / float / chuỗi, các đối tượng tùy ý, hoặc những gì? Nếu chúng là các kiểu dựng sẵn và có thể giữ cả hai x,ya,btheo thứ tự được sắp xếp, thì bạn có thể tránh được nhánh thứ hai. Lưu ý rằng việc tạo một tập hợp sẽ khiến mỗi một trong bốn phần tử x,y, a,bđược băm, có thể hoặc không tầm thường hoặc có hàm ý hiệu suất tùy thuộc hoàn toàn vào loại đối tượng chúng.
smci

18
Hãy ghi nhớ những người bạn làm việc cùng và loại dự án bạn đang phát triển. Tôi sử dụng một ít Python ở đây và ở đó. Nếu ai đó mã hóa một trong những câu trả lời ở đây, tôi hoàn toàn sẽ phải google những gì đang diễn ra. Điều kiện của bạn là có thể đọc được khá nhiều không có vấn đề gì.
Areks 18/10/19

3
Tôi sẽ không bận tâm với bất kỳ thay thế. Chúng ngắn gọn hơn, nhưng không rõ ràng (IMHO) và tôi nghĩ tất cả sẽ chậm hơn.
Barmar

22
Đây là một vấn đề XYAB cổ điển.
Tashus

5
Và nói chung nếu bạn đang xử lý các bộ sưu tập đối tượng độc lập theo thứ tự, hãy sử dụng bộ / dicts / vv. Đây thực sự là một vấn đề XY, chúng ta cần xem cơ sở mã lớn hơn mà nó được rút ra. Tôi đồng ý rằng ((x == a and y == b) or (x == b and y == a))có thể trông yukky, nhưng 1) ý định của nó rất rõ ràng và dễ hiểu đối với tất cả các lập trình viên không phải là Python, không phải là 2) trình biên dịch / trình biên dịch sẽ luôn xử lý tốt và về cơ bản nó không bao giờ có thể dẫn đến mã không hoạt động, không giống như lựa chọn thay thế. Vì vậy, 'thanh lịch hơn' cũng có thể có những nhược điểm nghiêm trọng.
smci

Câu trả lời:


151

Nếu các yếu tố có thể băm, bạn có thể sử dụng các bộ:

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

18
@Graham không, bởi vì có chính xác hai mục trong bộ bên phải. Nếu cả hai đều là a, không có b và nếu cả hai đều là b, thì không có a và trong cả hai trường hợp, các tập hợp không thể bằng nhau.
hobbs

12
Mặt khác, nếu chúng ta có ba yếu tố ở mỗi bên và chúng ta cần kiểm tra xem chúng có thể khớp với nhau không, thì các bộ sẽ không hoạt động. {1, 1, 2} == {1, 2, 2}. Tại thời điểm đó, bạn cần sortedhoặc Counter.
user2357112 hỗ trợ Monica

11
Tôi thấy điều này khó đọc (không đọc "{}" là "()"). Đủ để bình luận nó - và sau đó mục đích bị mất.
Édouard

9
Tôi biết đó là python nhưng việc tạo hai bộ mới chỉ để so sánh các giá trị có vẻ như quá mức đối với tôi ... Chỉ cần xác định một hàm thực hiện và gọi khi cần.
marxin

5
@marxin Một chức năng thậm chí còn quá mức cần thiết hơn 2 công trình thiết lập đơn giản. Và ít đọc hơn với 4 đối số.
Gloweye

60

Tôi nghĩ rằng điều tốt nhất bạn có thể nhận được là gói chúng thành các bộ dữ liệu:

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

Hoặc, có thể gói nó trong một tra cứu thiết lập

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

Ngay khi nó được đề cập bởi một vài bình luận, tôi đã thực hiện một số thời gian, và các bộ và bộ dường như thực hiện giống hệt ở đây khi việc tra cứu thất bại:

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

Mặc dù bộ dữ liệu thực sự nhanh hơn khi tra cứu thành công:

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

Tôi đã chọn sử dụng một bộ vì tôi đang thực hiện tra cứu thành viên và về mặt khái niệm, một bộ phù hợp hơn cho trường hợp sử dụng đó hơn là một tuple. Nếu bạn đo một sự khác biệt đáng kể giữa hai cấu trúc trong một trường hợp sử dụng cụ thể, hãy đi với cấu trúc nhanh hơn. Tôi không nghĩ rằng hiệu suất là một yếu tố ở đây mặc dù.


12
Phương pháp tuple trông rất sạch sẽ. Tôi lo ngại về tác động hiệu suất của việc sử dụng một bộ. Bạn có thể làm gì if (a, b) in ((x, y), (y, x)), mặc dù?
Brilliand

18
@Brilliand Nếu bạn lo lắng về tác động hiệu suất, Python không phải là ngôn ngữ dành cho bạn. :-D
Sneftel

Tôi thực sự thích phương pháp đầu tiên, hai so sánh tuple. Thật dễ dàng để phân tích (một mệnh đề tại một thời điểm) và mỗi mệnh đề rất đơn giản. Và trên hết, nó phải tương đối hiệu quả.
Matthieu M.

Có bất kỳ lý do để thích setgiải pháp trong câu trả lời cho giải pháp tuple từ @Brilliand?
dùng1717828

Một tập hợp yêu cầu các đối tượng có thể băm được, do đó, một tuple sẽ là một giải pháp tổng quát hơn với ít phụ thuộc hơn. Hiệu suất, trong khi có lẽ không quan trọng, cũng có thể trông rất khác nhau khi xử lý các vật thể lớn với băm đắt tiền và kiểm tra công bằng.
Dukeling

31

Tuples làm cho nó dễ đọc hơn một chút:

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

Điều này cho một manh mối: chúng tôi đang kiểm tra xem chuỗi x, ycó bằng chuỗi hay không a, bmà bỏ qua thứ tự. Đó chỉ là thiết lập bình đẳng!

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

,tạo ra một tuple, không phải là một danh sách vì vậy (x, y)(a, b)là các bộ dữ liệu, giống như x, ya, b.
Kissgyorgy

Tôi có nghĩa là "danh sách" theo nghĩa "thứ tự các yếu tố", không phải theo nghĩa của listloại Python . Chỉnh sửa vì thực sự điều này là khó hiểu.
Thomas

26

Nếu các mục không thể băm, nhưng hỗ trợ so sánh đặt hàng, bạn có thể thử:

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

Vì điều này cũng hoạt động với các mục có thể băm (phải không?), Đó là một giải pháp toàn cầu hơn.
Carl Witthoft

5
@CarlWitthoft: Không. Có những loại có thể băm nhưng không thể sắp xếp: complexví dụ.
dan04

26

Cách thanh lịch nhất, theo tôi, sẽ là

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

Đây là một cách tốt hơn so với sử dụng các tập hợp, {a, b} == {y, x}như được chỉ ra trong các câu trả lời khác bởi vì chúng ta không cần phải suy nghĩ nếu các biến có thể băm được.


Làm thế nào để điều này khác với câu trả lời trước đó ?
scohe001

5
@ scohe001 Nó sử dụng một tuple trong đó câu trả lời trước đó sử dụng một bộ. Câu trả lời trước đó đã xem xét giải pháp này, nhưng từ chối liệt kê nó như một khuyến nghị.
Brilliand

25

Nếu đây là những con số, bạn có thể sử dụng (x+y)==(a+b) and (x*y)==(a*b).

Nếu đây là những mặt hàng tương đương, bạn có thể sử dụng min(x,y)==min(a,b) and max(x,y)==max(a,b).

Nhưng ((x == a and y == b) or (x == b and y == a))là rõ ràng, an toàn, và tổng quát hơn.


2
Haha, đa thức đối xứng ftw!
Carsten S

2
Tôi nghĩ rằng điều này tạo ra nguy cơ lỗi tràn.
Razvan Socol

3
Đây là câu trả lời đúng, đặc biệt là câu cuối cùng. Hãy đơn giản, điều này không cần nhiều lần lặp mới hoặc bất cứ điều gì tương tự. Đối với những người muốn sử dụng các tập hợp, hãy xem việc triển khai các đối tượng tập hợp và sau đó tưởng tượng thử chạy nó trong một vòng lặp chặt chẽ ...
Z4-tier

3
@RazvanSocol OP không cho biết các loại dữ liệu là gì và câu trả lời này đủ điều kiện cho các giải pháp phụ thuộc vào loại.
Z4-tier

21

Là một khái quát cho hơn hai biến chúng ta có thể sử dụng itertools.permutations. Đó là thay vì

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

chúng tôi có thể viết

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

Và tất nhiên hai phiên bản biến:

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

5
Câu trả lời chính xác. Điều đáng nói ở đây (đối với những người chưa làm được nhiều với máy phát điện trước đây) rằng điều này rất hiệu quả về bộ nhớ, vì chỉ một lần hoán vị được tạo ra và kiểm tra "trong" sẽ dừng và trả về True ngay sau khi trận đấu được tìm thấy.
robertlayton

2
Cũng đáng chỉ ra rằng sự phức tạp của phương pháp này là O(N*N!) ; Đối với 11 biến, điều này có thể mất hơn một giây để kết thúc. (Tôi đã đăng một phương thức nhanh hơn, nhưng vẫn cần O(N^2)và bắt đầu chiếm một giây trên 10k biến; Vì vậy, có vẻ như điều này có thể được thực hiện nhanh hoặc nói chung (wrt. Hashable / orderability), nhưng không phải cả hai: P)
Aleksi Torhamo

15

Bạn có thể sử dụng các bộ dữ liệu để thể hiện dữ liệu của mình và sau đó kiểm tra để bao gồm thiết lập, như:

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

    return (x, y) in test_set

3
Được viết dưới dạng một lớp lót và với một danh sách (đối với các mặt hàng không thể băm), tôi sẽ coi đây là câu trả lời tốt nhất. (mặc dù tôi là một người mới hoàn thành Python).
Édouard

1
@ Édouard Bây giờ có một câu trả lời khác về cơ bản là như vậy (chỉ với một tuple thay vì một danh sách, dù sao thì hiệu quả hơn).
Brilliand

10

Bạn đã có giải pháp dễ đọc nhất . Có nhiều cách khác để diễn đạt điều này, có lẽ với ít ký tự hơn, nhưng chúng ít thẳng thắn hơn để đọc.

Tùy thuộc vào những gì các giá trị thực sự đại diện cho đặt cược tốt nhất của bạn là bọc séc trong một chức năng bằng một tên nói . Ngoài ra, ngoài ra, bạn có thể mô hình hóa các đối tượng x, y và a, b trong các đối tượng lớp chuyên dụng cao hơn mà sau đó bạn có thể so sánh với logic so sánh trong phương thức kiểm tra đẳng thức lớp hoặc hàm tùy chỉnh chuyên dụng.


3

Có vẻ như OP chỉ quan tâm đến trường hợp của hai biến, nhưng vì StackOverflow cũng dành cho những người tìm kiếm cùng một câu hỏi sau đó, tôi sẽ cố gắng giải quyết trường hợp chung ở đây một cách chi tiết; Một câu trả lời trước đã có câu trả lời chung chung bằng cách sử dụng itertools.permutations(), nhưng phương pháp đó dẫn đến O(N*N!)so sánh, vì có N!hoán vị vớiN các mục. (Đây là động lực chính cho câu trả lời này)

Trước tiên, hãy tóm tắt làm thế nào một số phương pháp trong các câu trả lời trước áp dụng cho trường hợp chung, như là động lực cho phương pháp được trình bày ở đây. Tôi sẽ sử dụng Ađể tham khảo (x, y)Btham khảo(a, b) , có thể là các bộ dữ liệu có độ dài tùy ý (nhưng bằng nhau).

set(A) == set(B)là nhanh, nhưng chỉ hoạt động nếu các giá trị có thể băm và bạn có thể đảm bảo rằng một trong các bộ dữ liệu không chứa bất kỳ giá trị trùng lặp nào. (Ví dụ.{1, 1, 2} == {1, 2, 2} như được chỉ ra bởi @ user2357112 dưới câu trả lời của @Daniel Mesejo)

Phương thức trước có thể được mở rộng để hoạt động với các giá trị trùng lặp bằng cách sử dụng từ điển với số đếm, thay vì bộ: (Điều này vẫn có giới hạn là tất cả các giá trị cần phải được băm, ví dụ: các giá trị có thể thay đổi như listsẽ không hoạt động)

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)không yêu cầu giá trị có thể băm, nhưng chậm hơn một chút và thay vào đó yêu cầu giá trị có thể sắp xếp. (Vì vậy, ví dụ như complexsẽ không làm việc)

A in itertools.permutations(B)không yêu cầu các giá trị có thể băm hoặc có thể sắp xếp, nhưng như đã đề cập, nó có O(N*N!)độ phức tạp, vì vậy ngay cả chỉ với 11 mục, nó có thể mất hơn một giây để hoàn thành.

Vì vậy, có cách nào để chung chung, nhưng làm nó nhanh hơn đáng kể? Tại sao có, bằng cách "kiểm tra" thủ công rằng có cùng số lượng của từng mặt hàng: (Độ phức tạp của mặt hàng này là O(N^2), vì vậy điều này cũng không tốt cho đầu vào lớn; Trên máy của tôi, 10k mặt hàng có thể chiếm một giây - nhưng với đầu vào nhỏ hơn, như 10 mục, điều này cũng nhanh như các mục khác)

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

Để có được hiệu suất tốt nhất, trước tiên, người ta có thể muốn thử dictphương thức dựa trên cơ sở, quay lại sortedphương thức dựa trên cơ sở nếu điều đó không thành công do các giá trị không thể thực hiện được và cuối cùng quay lại countphương thức dựa trên cơ sở nếu quá thất bại do các giá trị không thể sắp xếp được.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.