2013-01-04 55 views
5

Xin lỗi nếu điều này đã được trả lời ở nơi khác; Tôi đã thử tìm kiếm, nhưng không tìm thấy bất cứ điều gì mà trả lời câu hỏi của tôi (hoặc có lẽ tôi có, nhưng không hiểu nó) ...Python - Sắp xếp các yếu tố trong danh sách các danh sách

Tôi khá mới với Python (v2.6.2) và có một danh sách liệt kê chứa nổi giá trị điểm mà trông giống như sau (trừ điều hoàn toàn có 2+ triệu mục cho mỗi danh sách):

cat = [[152.123, 150.456, 151.789, ...], [4.123, 3.456, 1.789, ...], [20.123, 22.456, 21.789, ...]] 

Bây giờ những gì tôi muốn làm là sắp xếp tất cả 3 của danh sách theo thứ tự tăng dần của các yếu tố trong danh sách thứ 3, chẳng hạn như tôi nhận được:

cat_sorted = [[152.123, 151.789, 150.456, ...], [4.123, 1.789, 3.456, ...], [20.123, 21.789, 22.456, ...]] 

Tôi đã thử một vài điều, nhưng họ không cho tôi những gì tôi đang tìm kiếm (hoặc có lẽ tôi đang sử dụng chúng không chính xác). Có cách nào để làm những gì tôi đang tìm kiếm không và nếu có, thì cách nào đơn giản nhất là & nhanh nhất (xem xét tôi có 3 x 2 triệu mục)? Có cách nào để phân loại một danh sách bằng cách sử dụng danh sách khác không?

+0

Chỉ cần tự hỏi đó là vấn đề gì và python có thực sự phù hợp với điều này không? Tôi đã không nhìn thấy bất kỳ trường hợp sử dụng python cho các nhiệm vụ với số lượng dữ liệu như vậy .. – Ixanezis

Trả lời

8

này sẽ là đau đớn, nhưng sử dụng python mặc định, bạn có 2 lựa chọn:

  • trang trí 1 và danh sách thứ 2 với enumerate(), sau đó sắp xếp những sử dụng các chỉ số để tham khảo giá trị từ danh sách thứ 3 :

    cat_sorted = [ 
        [e for i, e in sorted(enumerate(cat[0]), key=lambda p: cat[2][p[0]])], 
        [e for i, e in sorted(enumerate(cat[1]), key=lambda p: cat[2][p[0]])], 
        sorted(cat[2]) 
    ] 
    

    mặc dù nó có thể giúp sắp xếp cat[2] tại chỗ thay vì sử dụng sorted(); bạn không thể đi lại bằng cách sử dụng sorted() cho hai người còn lại.

  • zip() ba danh sách với nhau, sau đó sắp xếp vào các yếu tố thứ ba trong danh sách mới này của danh sách, sau đó zip() một lần nữa để trở lại cấu trúc ban đầu:

    from operator import itemgetter 
    cat_sorted = zip(*sorted(zip(*cat), key=itemgetter(2))) 
    

Cả sẽ là một hiệu suất buster, không phải với các danh sách python đơn giản của hàng triệu con số.

+0

đây là một giải pháp tuyệt vời! –

+0

Khi tôi đã tìm hiểu ý nghĩa của OP và cách mô tả khớp với đầu vào và đầu ra mẫu, tâm trí của tôi lập tức nhảy vào phương thức 'zip' mà bạn hiển thị. Mô tả sự cố như được đưa ra cho thấy rằng dữ liệu không thực sự được tổ chức đúng cách để bắt đầu; 'zip' hacks xung quanh thanh lịch đó. –

+0

Rực rỡ. Giải pháp thứ hai với lệnh zip hoạt động hoàn hảo. Cảm ơn đã giúp đỡ! :) – Shanagar

4

Nếu bạn sẵn sàng sử dụng thư viện bổ sung, tôi đề xuất Python Pandas. Nó có một đối tượng DataFrame tương tự như của R data.frame và chấp nhận một danh sách các danh sách trong hàm tạo, mà sẽ tạo ra một mảng dữ liệu 3 cột. Sau đó, bạn có thể dễ dàng sử dụng chức năng được xây dựng trong pandas.DataFrame.sort để sắp xếp theo cột thứ ba (tăng dần hoặc giảm dần).

Có nhiều cách Python đơn giản để thực hiện việc này, nhưng với kích thước của vấn đề của bạn, việc sử dụng các hàm được tối ưu hóa trong Pandas là một cách tiếp cận tốt hơn. Và nếu bạn cần bất kỳ loại thống kê tổng hợp từ dữ liệu được sắp xếp của bạn, sau đó Pandas là không có trí tuệ cho việc này.

+0

+1 để sử dụng Pandas - đó là những gì tôi đang trong quá trình viết. Các câu trả lời khác là đúng nhưng đối với các dữ liệu lớn như vậy, một thư viện như Pandas là những gì bạn thực sự muốn. – Iguananaut

2

Cách tiếp cận chung tôi sẽ thực hiện là thực hiện schwartzian transform trên toàn bộ điều.

Nén ba danh sách lại với nhau thành danh sách các bộ dữ liệu.

Sắp xếp các bộ dữ liệu bằng phần tử thứ ba làm khóa.

lặp qua danh sách các bộ dữ liệu mới được sắp xếp và điền lại vào ba danh sách.

1

Đối với mục đích hoàn chỉnh, một giải pháp sử dụng NumPy:

import numpy as np 

cat = [[152.123, 150.456, 151.789], 
     [4.123, 3.456, 1.789], 
     [20.123, 22.456, 21.789]] 

cat = np.array(cat) 
cat_sorted = cat[:, cat[2].argsort()] 

print cat_sorted 
[[ 152.123 151.789 150.456] 
[ 4.123 1.789 3.456] 
[ 20.123 21.789 22.456]] 
0

Đây là một cách khác để làm điều đó dựa trên các câu trả lời tuyệt vời bằng cách Martijn Pieters và pcalcao

def sort_by_last(ll): 
    """ 
     >>> sort_by_last([[10, 20, 30], [3, 2, 1]]) 
     [[30, 20, 10], [1, 2, 3]] 

     >>> sort_by_last([[10, 20, 30], [40, 50, 60], [3, 2, 1]]) 
     [[30, 20, 10], [60, 50, 40], [1, 2, 3]] 

     >>> sort_by_last([[10, 20, 30], [40, 50, 60], [1, 1, 1]]) 
     [[10, 20, 30], [40, 50, 60], [1, 1, 1]] 

     >>> sort_by_last([[10, 20, 30], [40, 50, 60], [1, 3, 1]]) 
     [[10, 30, 20], [40, 60, 50], [1, 1, 3]] 

     >>> sort_by_last([[152.123, 150.456, 151.789], [4.123, 3.456, 1.789], [20.123, 22.456, 21.789]]) 
     [[152.123, 151.789, 150.456], [4.123, 1.789, 3.456], [20.123, 21.789, 22.456]] 
    """ 
    return [sorted(x, key=lambda y: ll[-1][x.index(y)]) for x in ll] 

Chuỗi lớn có là một docstring với doctest, để kiểm tra chức năng sao chép nó vào một tập tin và chạy nó với python -m doctest -v <file>

+0

Việc sting ở đây là 'x.index()' sẽ làm cho sắp xếp khá chậm đối với các danh sách lớn –

0

Ở đây, keys là danh sách các chỉ mục được sắp xếp.

keys = sorted(range(len(cat[2])), key=cat[2].__getitem__) 
cat_sorted = [[cat[i][k] for k in keys] for i in range(3)] 
Các vấn đề liên quan