2013-06-03 35 views
7

Tôi có một danh sách các trường hợp từ cùng một lớp và tôi muốn làm cho danh sách của mình riêng biệt dựa trên một thuộc tính trong lớp học. Cách pythonic nhất để đạt được điều này là gì?Làm thế nào để tạo danh sách bằng Python khác biệt dựa trên thuộc tính của lớp trong danh sách?

Dưới đây là một số mẫu mã:

#!/usr/bin/python 
#-*- coding:utf-8 -*- 

class MyClass(object): 
    def __init__(self, classId, tag): 
     self.classId = classId 
     self.tag = tag 

myList = [] 

myInstance1 = MyClass(1, "ABC") 
myInstance2 = MyClass(2, "DEF") 
myInstance3 = MyClass(3, "DEF") 

myList.append(myInstance1) 
myList.append(myInstance3) # note that the order is changed deliberately 
myList.append(myInstance2) 

Nếu tôi muốn sắp xếp danh sách của tôi bây giờ dựa trên một trong các thuộc tính trong MyClass, tôi thường chỉ sắp xếp nó theo mã, và thiết lập phím sử dụng một biểu thức lambda - như thế này:

myList.sort(key=lambda x: x.classId) 
for x in myList: 
    print x.classId 

$ python ./test.py 
1 
2 
3 

Có thể sử dụng phương pháp tương tự (lambda, bản đồ hoặc tương tự) để tạo danh sách riêng biệt dựa trên thuộc tính "thẻ" không? Ngoài ra, nếu điều này là có thể, nó là cách "pythonic" nhất để làm cho một danh sách riêng biệt dựa trên một tài sản của một lớp học trong danh sách đó?

Tôi đã cố gắng tìm kiếm cả SO và Google cho các chủ đề về vấn đề này, nhưng tất cả các kết quả tôi thấy xử lý với danh sách đơn giản mà chỉ chứa một giá trị số và không phải là một đối tượng tùy chỉnh ..

Trả lời

6

Giả sử các tài sản mà bạn Rất mong để chìa khóa trên là không thay đổi, bạn có thể sử dụng một dict:

d = {} 
for x in xs: 
    d[x.tag] = x 

Bây giờ d sẽ chứa một đơn x mỗi giá trị tag; bạn có thể sử dụng d.values() hoặc d.itervalues() để lấy số xs.

NB. ở đây mục phù hợp cuối cùng sẽ thắng; để giành chiến thắng đầu tiên, lặp lại ngược lại.

+0

Một khi bạn cũng sử dụng bộ lọc() (http://docs.python.org/2/library/functions. html # filter) sẽ nhanh hơn một chút vì nội tuyến cho vòng lặp. – pypat

+0

Cảm ơn bạn. Điều này (sử dụng từ điển) hoạt động, nhưng nó là cách "tốt nhất" để đạt được nó? Các giải pháp được đề xuất bởi pypat có vẻ thêm pythonic. – v3gard

+1

@pypat: Tôi đoán bạn có thể, với biến vị ngữ thêm các giá trị trước đó không nhìn thấy vào dict, hoặc thực sự chỉ là một tập hợp: 's = set()', sau đó 'filter (lambda x: False nếu x.tag trong s else (s.add (x.tag) hoặc True), myList) '. Cám ơn vì sự gợi ý! Phiên bản 'for'-and-dict dựa trên cảm thấy đơn giản hơn với tôi, vì vậy tôi sẽ chuẩn bị trước khi chuyển đổi. –

9

Bạn có thể sử dụng python dict comprehension

{x.tag: x for x in myList}.values() 

Ví dụ của bạn:

>>> class MyClass(object): 
...  def __init__(self, classId, tag): 
...   self.classId = classId 
...   self.tag = tag 
... 
>>> myList = [MyClass(1, "ABC"), MyClass(2, "DEF"), MyClass(3, "DEF")] 
>>> uniqList = {x.tag: x for x in myList}.values() 
>>> print [x.classId for x in uniqList] 
[1, 3]