2012-05-03 18 views
13

Tôi hiểu rằng các phần tử của bộ python không được đặt hàng. Gọi phương thức pop trả về một phần tử tùy ý; Tôi ổn với điều đó.Trong python, được set.pop() xác định?

Điều tôi tự hỏi là liệu pop có luôn trả về cùng một phần tử khi tập hợp có cùng một lịch sử hay không. Trong một phiên bản của python tất nhiên, tôi không nhớ nếu phiên bản khác nhau/triển khai của python làm điều riêng của họ. Đặc biệt, tôi hỏi về python 2.7. Đó là vấn đề thực hiện nhiều hơn api trong trường hợp này.

Tôi đang sử dụng nhiều bộ trong trình tạo dungeon thủ tục cho một trò chơi và tôi muốn kết quả là xác định cho một hạt giống nhất định.

+1

Related: http://stackoverflow.com/questions/3949310/how-is-cpythons-set-implemented và http://svn.python.org/view/python/trunk/Objects/setobject.c?view = markup – ChristopheD

+1

Tại sao không kiểm tra nó/nhìn vào nguồn? – Marcin

+0

@delnan "Đặc biệt, tôi hỏi về python 2.7. Đó là vấn đề thực hiện nhiều hơn api trong trường hợp này." Vì vậy, không cần phải kiểm tra một số phiên bản hoặc các phiên bản trong tương lai như bạn đề xuất. Bạn dường như đã tưởng tượng ra một yêu cầu về tính di động và vĩnh cửu. – Marcin

Trả lời

18

Câu trả lời nói chung là không. Nguồn python @Christophe và @Marcin (un) trợ giúp chỉ ra rằng các phần tử được xuất hiện theo thứ tự chúng xuất hiện trong bảng băm. Vì vậy, thứ tự pop (và có lẽ là thứ tự lặp lại) xác định, nhưng chỉ cho cố định giá trị băm. Đó là trường hợp đối với số nhưng không cho các chuỗi, theo Note trong tài liệu của __hash__, mà tình cờ cũng chạm vào câu hỏi của bạn trực tiếp:

Lưu ý theo mặc định băm() giá trị các đối tượng str, bytes và datetime được "salted" với giá trị ngẫu nhiên không thể đoán trước. Mặc dù chúng vẫn không đổi trong một tiến trình Python riêng lẻ, chúng không thể dự đoán được giữa các lời gọi lặp lại của Python.

[...]

Thay đổi giá trị băm ảnh hưởng đến trật tự lặp của dicts, bộ và các ánh xạ khác. Python chưa bao giờ đảm bảo về thứ tự này (và nó thường thay đổi giữa các bản dựng 32 bit và 64 bit).

Edit: Như @Marcin chỉ ra, các liên kết Tôi trích dẫn không áp dụng cho Python 2. Hash ngẫu nhiên became the default with Python 3.3. Python 2.7 không có cố ý không xác định chuỗi băm theo mặc định.

Nói chung, đây là vấn đề đối với bất kỳ đối tượng nào có hàm băm không phải là hàm có thể lặp lại về giá trị của nó (ví dụ: nếu hàm băm dựa trên địa chỉ bộ nhớ). Nhưng ngược lại, nếu bạn định nghĩa phương thức __hash__ của riêng mình cho các đối tượng trong bộ của mình, bạn có thể mong đợi rằng chúng sẽ được trả về theo thứ tự có thể lặp lại. (Cung cấp lịch sử của bộ và nền tảng được giữ cố định).

+1

Bạn đang tham khảo tài liệu cho phiên bản dev của python. Câu hỏi này là về python 2.7 và văn bản bạn trích dẫn không xuất hiện trong tài liệu tương ứng cho phiên bản đó: http://docs.python.org/reference/datamodel.html # object .__ hash__ – Marcin

+0

Cảm ơn bạn đã phát hiện ra điều đó! – alexis

4

The documentation không chỉ định rằng nó phải xác định, do đó bạn nên cho rằng nó không phải là xác định.

+2

Cho rằng câu hỏi có vẻ là về một phiên bản cụ thể, không cần phải giả định bất cứ điều gì - nguồn có thể được kiểm tra và kiểm tra hành vi. – Marcin

6

Nội bộ Tôi nghĩ rằng tình huống tương tự như dict. Thứ tự được xác định bằng thuật toán băm, trong đó trong một số trường hợp sẽ mang lại kết quả tương tự. Nhưng bạn không nên phụ thuộc vào điều đó, vì một khi số lượng các phần tử được lớn, bộ sẽ gặp phải va chạm (đó là băm nội bộ), mà cuối cùng dẫn đến một thứ tự khác nhau.

Tóm lại: Không, set.pop() không xác định. Đừng cho rằng bất kỳ thứ tự, vì API khẳng định một cách rõ ràng, rằng

một đối tượng thiết lập là một bộ sưu tập có thứ tự

1

Nếu bạn muốn ép buộc xác định, bạn có thể thử một cái gì đó như

value = min(my_set) 
my_set.remove(value) 
+2

lưu ý rằng đây chỉ là xác định khi min() rõ ràng. Có thể có một tập hợp kỳ lạ với các giá trị riêng biệt có hai hoặc nhiều hơn tất cả đều nhỏ hơn tất cả các giá trị khác (và cả hai đều nhỏ hơn giá trị kia). không phổ biến trong tự nhiên, nhưng có thể. – ch3ka

+2

Một ví dụ tốt hơn sẽ là các giá trị mà không thể đặt hàng đơn giản (tức là chỉ có thể được so sánh cho bình đẳng). Một định nghĩa '__lt__' cho phép' x

+2

khi tập hợp không thể được đặt hàng (ví dụ: một tập các số phức), giải pháp của bạn sẽ thất bại với TypeError. Nhưng hãy xem xét 'lớp epsilon (float): def __lt __ (tự, khác): trả về True nếu 0 ch3ka

-1

Nếu bạn thực sự đang nhắm mục tiêu một phiên bản đặc biệt của trăn, sau đó bạn có thể nhìn vào các nguồn, và kiểm tra hành vi của mình (nhưng kiểm tra tốt - xem xét các yếu tố tải và các loại tương tự).

Nếu bạn muốn tính di động, hoặc bạn thấy set không hoạt động theo yêu cầu, hãy sử dụng lệnh đã đặt hàng (đây là một: http://code.activestate.com/recipes/576693/; có rất nhiều người khác, vì vậy hãy tìm một người bạn thích giao diện) và điều chỉnh nó như một bộ.

Cập nhật: đây là một tập có thứ tự: http://packages.python.org/Brownie/api/datastructures.html#brownie.datastructures.OrderedSet

+0

Ordereddict ở dạng stdlib trong 2.7 và 3.1+ (http://docs.python.org/library/collections.html # collections.OrderedDict, http://docs.python.org/dev/library/collections.html#collections.OrderedDict) – miku

+0

@miku Cho rằng nó được triển khai trong C, không thể điều chỉnh được một cách hợp lý, như được chỉ định trong cùng một câu bạn đang trả lời. – Marcin

Các vấn đề liên quan