2010-03-30 43 views

Trả lời

10

Giống như mọi người khác đã chỉ ra, từ điển có đặt hàng riêng của họ và bạn có thể không chỉ sắp xếp chúng như bạn sẽ một danh sách.

Một điều tôi muốn nói thêm là, nếu bạn chỉ muốn đi qua các yếu tố của một cuốn từ điển theo thứ tự sắp xếp, đó chỉ là:

for k in sorted(a): 
    print k, a[k] # or whatever. 

Nếu bạn muốn có một danh sách hiểu (mỗi Alex):

sortedlist = [(k, a[k]) for k in sorted(a)] 

tôi muốn chỉ ra rằng việc sử dụng key=int Alex sẽ không làm việc với ví dụ của bạn bởi vì một trong những chìa khóa của bạn là 'test'. Nếu bạn thực sự muốn anh số được sắp xếp trước khi phi numerics, bạn sẽ phải vượt qua trong một hàm cmp:

def _compare_keys(x, y): 
    try: 
     x = int(x) 
    except ValueError: 
     xint = False 
    else: 
     xint = True 
    try: 
     y = int(y) 
    except ValueError: 
     if xint: 
      return -1 
     return cmp(x.lower(), y.lower()) 
     # or cmp(x, y) if you want case sensitivity. 
    else: 
     if xint: 
      return cmp(x, y) 
     return 1 

for k in sorted(a, cmp=_compare_keys): 
    print k, a[k] # or whatever. 

Hoặc có thể bạn biết đủ về phím của bạn để viết một chức năng để chuyển đổi chúng thành một chuỗi (hoặc đối tượng khác) sắp xếp đúng:

# Won't work for integers with more than this many digits, or negative integers. 
MAX_DIGITS = 10 
def _keyify(x): 
    try: 
     xi = int(x) 
    except ValueError: 
     return 'S{0}'.format(x) 
    else: 
     return 'I{0:0{1}}'.format(xi, MAX_DIGITS) 

for k in sorted(a, key=_keyify): 
    print k, a[k] # or whatever. 

Điều này sẽ nhanh hơn nhiều so với sử dụng chức năng cmp.

+0

Tôi không thực sự thích điều này nhiều như các giải pháp khác. '_keyify' là không cần thiết cứng nhắc và tôi không nghĩ rằng khá sạch sẽ như một số giải pháp khác và' _compare_keys' của bạn sử dụng 'cmp', mà thường là một dấu hiệu xấu. (Nó cũng là hình thức tốt để giữ cho các khối 'try' cho' try'/'except' càng nhỏ càng tốt. Tôi sẽ đặt' return 'I {0: 0 {1}}' dạng (xi, MAX_DIGITS) 'trong một 'else' block.) –

+0

Không, các giải pháp không được tối ưu hóa, chúng chỉ có các ví dụ hoặc điểm bắt đầu. (Thật khó để đề xuất một giải pháp tốt hơn mà không biết tên miền chính thực sự là gì.) Tôi thích giải pháp của bạn ngoại trừ phần mà nó bị hỏng trong Python 3. Ban đầu tôi viết '_compare_keys' với hai khối' try' hai dòng, nhưng nó dài gấp đôi. Sử dụng các khối 'try' để kiểm soát luồng thực thi đã loại bỏ sự cần thiết của một boolean' yint'. –

+0

Tôi giả định rằng bạn có nghĩa là sử dụng tham số 'cmp', trái ngược với hàm, là một" dấu hiệu xấu ", và có nó là, nhưng nó được đưa vào bởi miền khóa không được xác định đầy đủ. Đó là lý do tại sao tôi tiếp tục với giải pháp '_keyify'. Thậm chí tốt hơn là tạo một lớp mới cho các khóa có thể lấy đầu vào chuỗi và sắp xếp chính xác, và sử dụng nó làm khóa của từ điển thay vào đó, nhưng tôi không biết liệu ben có kiểm soát nhiều hơn từ điển đầu vào hay không. Và, vâng, tôi quên mất 'khối khác'; quá nhiều C++ gần đây. Đã sửa. –

4

Từ điển không có thứ tự. Bạn không thể sắp xếp một cái như bạn hiển thị vì kết quả a là một dict, và dicts không có thứ tự.

Nếu bạn muốn, chẳng hạn, một danh sách danh sách các phím theo thứ tự sắp xếp, bạn có thể sử dụng mã như

>>> def my_key(dict_key): 
...  try: 
...   return int(dict_key) 
...  except ValueError: 
...   return dict_key 
... 
>>> sorted(a, key=my_key) 
['1', '6', '67', '88', '100', 'test'] 

này dựa trên hành vi Python ngu ngốc rằng trường hợp của str luôn lớn hơn trường hợp của int. Trong một thiết kế tối ưu, các phím của dict của bạn sẽ là những thứ bạn có thể so sánh một cách an toàn và bạn sẽ không trộn lẫn trong các chuỗi đại diện cho các số với các chuỗi đại diện cho các từ.

Nếu bạn muốn giữ các phím theo thứ tự luôn được sắp xếp, bạn có thể sử dụng mô-đun bisect hoặc triển khai ánh xạ dựa trên cấu trúc dữ liệu cây. Mô-đun bisect không chấp nhận đối số key như công cụ sắp xếp vì điều này sẽ có khả năng không hiệu quả; bạn sẽ sử dụng mẫu trang trí-sử dụng-undecorate nếu bạn chọn sử dụng bisect, giữ một danh sách được sắp xếp phụ thuộc vào kết quả của hàm phím.

+0

Lưu ý rằng việc duy trì danh sách được sắp xếp bằng bisect sẽ mất thời gian O (n ** 2). Bisect sẽ tìm đúng nơi để chèn vào thời gian O (log n) trên mỗi mục, nhưng quá trình chèn vẫn mất thời gian O (n) cho mỗi mục do bản chất giống như mảng của các danh sách Python. –

+0

@Daniel Strutzbach, Điều đó phụ thuộc vào ý bạn bằng cách "duy trì"; tùy thuộc vào cách sử dụng bạn thường có thể tránh được hành vi bậc hai của việc xây dựng một danh sách được sắp xếp bằng cách sử dụng insort. Sử dụng một danh sách và 'bisect' chắc chắn không cung cấp hiệu suất lý tưởng cho các hoạt động chèn. Nếu các hoạt động này là quan trọng, tốt hơn là nên thực hiện "hoặc thực hiện ánh xạ dựa trên cấu trúc dữ liệu cây". Vì bạn đã thực hiện việc này cho chúng tôi, tôi đã upvoted bài đăng của bạn có tham chiếu đến việc thực hiện 'sortdict' tốt đẹp của bạn. –

6

Bạn không thể sắp xếp dict bằng Python vì loại dict vốn không có thứ tự. Những gì bạn có thể làm là sắp xếp các mục trước khi bạn sử dụng chúng bằng chức năng dựng sẵn sorted(). Bạn cũng sẽ cần một hàm helper để phân biệt giữa số và chuỗi của bạn phím:

def get_key(key): 
    try: 
     return int(key) 
    except ValueError: 
     return key 
a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 } 
print sorted(a.items(), key=lambda t: get_key(t[0])) 

Tuy nhiên trong Python 3.1 (và 2.7) module collections chứa collections.OrderedDict loại có thể được sử dụng để đạt được hiệu quả mong muốn như dưới đây :

def get_key(key): 
    try: 
     return int(key) 
    except ValueError: 
     return key 
a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 } 
b = collections.OrderedDict(sorted(a.items(), key=lambda t: get_key(t[0]))) 
print(b) 
+0

Điều này sẽ không nhận được đơn đặt hàng mà OP muốn. –

+0

Hi Mawushe, Trước tiên hãy để tôi cảm ơn bạn đã đề xuất của bạn. Nhưng vẫn là mã đã cho sẽ không cung cấp một giải pháp mong muốn. – Joseph

+0

Cả hai đều là gents đúng Tôi đã cập nhật câu trả lời cho cả hai sắp xếp theo chìa khóa và đưa vào tài khoản bản chất chuỗi của các phím. –

5

9 năm trước, tôi đăng tải một recipe rằng bắt đầu

Không thể sắp xếp từ điển - một ánh xạ không có thứ tự!

và cho biết cách sắp xếp liệt kê ngoài khóa và giá trị của dict.

Với Python hiện nay, và thông số kỹ thuật-cộng-ngụ ý bày tỏ của bạn, tôi muốn đề nghị:

import sys 

def asint(s): 
    try: return int(s), '' 
    except ValueError: return sys.maxint, s 

sortedlist = [(k, a[k]) for k in sorted(a, key=asint)] 

các key=asint là những gì nói với sorted để điều trị những phím chuỗi như số nguyên để phân loại mục đích, do đó ví dụ '2' các loại giữa '1''12', thay vì sau cả hai - đó là những gì bạn xuất hiện để yêu cầu, cũng như có tất cả các phím không phải chữ số tất cả phân loại sau tất cả tất cả các chữ số. Nếu bạn cũng cần phải đối phó với tất cả các chữ số chuỗi chính thể hiện số nguyên lớn hơn sys.maxint, nó phức tạp hơn một chút, nhưng vẫn có thể làm được:

class Infinity(object): 
    def __cmp__(self, other): return 0 if self is other else 1 
infinite = Infinity() 
def asint(s): 
    try: return int(s), '' 
    except ValueError: return infinite, s 

Nói chung, bạn có thể nhận được câu trả lời tốt hơn nhanh hơn nếu bạn chỉ định các yêu cầu chính xác của bạn chính xác hơn từ khi bắt đầu ;-).

+0

Điều này sẽ thất bại cho đầu vào OP được chỉ định vì 'int' sẽ tăng' ValueError' khi nó gặp ''test''. –

+0

@ Giống như vậy, phải - hãy để tôi sửa lỗi đó. –

+0

Hi Alex, Cảm ơn sự giúp đỡ và lời khuyên tốt bụng của các bạn. Nó đã làm việc...! – Joseph

2

Nếu bạn cài đặt gói blist của mình, gói này bao gồm loại sorteddict. Sau đó, bạn có thể chỉ đơn giản là:

from blist import sorteddict 

def my_key(dict_key): 
     try: 
       return int(dict_key) 
     except ValueError: 
       return dict_key 

a = {'100':12,'6':5,'88':3,'test':34, '67':7,'1':64 } 
print sorteddict(my_key, **a).keys() 

Output:

['1', '6', '67', '88', '100', 'test'] 
+0

7 dấu cách không gian sang một bên ';)', đây là một giải pháp tốt nếu bạn cần một ánh xạ luôn được sắp xếp. –

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