2015-08-25 10 views
6

Tôi đang viết một công cụ tối ưu hóa nhỏ để mua tem tại bưu điện.Sắp xếp một từ điển Python phức tạp chỉ bằng một trong các giá trị của nó

Trong quá trình này Tôi đang sử dụng một cuốn từ điển, mà tôi đang sắp xếp theo những gì tôi học được trong "nổi tiếng" khác câu hỏi này: Sort a Python dictionary by value

Trong trường hợp của tôi từ điển của tôi là hơi phức tạp hơn:
- một bốn-mục-tuple để làm cho chính
- và một lăm-item-tuple để làm cho dữ liệu.

Nguồn gốc của từ điển này là một sự lặp lại, trong đó mỗi vòng lặp thành công được thêm một dòng:

MyDicco[A, B, C, D] = eval, post, number, types, over 

Đây chỉ là một ví dụ nhỏ của một hoạt động tầm thường, cố gắng cho 75 cent:
{
(0, 0, 1, 1): (, 75, 2, 2, 0)
(0, 0, 0, 3): (, 75, 3, 1, 0)
(0, 0, 2, 0): (, 100, 2, 1, 25)
(0, 1, 0, 0): (, 200, 1, 1, 125)
(1, 0, 0, 0): (27.511, 350, 1, 1, 275)
}

cho đến nay tôi đang sử dụng mã này để sắp xếp (được đang làm việc):

MyDiccoSorted = sorted(MyDicco.items(), key=operator.itemgetter(1)) 

tôi đang sắp xếp theo đánh giá-score của tôi, bởi vì phân loại là tất cả về việc đưa giải pháp tốt nhất lên hàng đầu. Điểm đánh giá chỉ là một điểm dữ liệu trong số 5 mục-tuple (trong ví dụ đó là điểm đánh giá: 22, 31, 2521, 12511 và 27511).

Như bạn có thể thấy trong ví dụ trên, nó sắp xếp (như tôi muốn) bởi bộ tuple thứ hai, chỉ mục 1. Nhưng tôi phải (gắt gỏng) mang "điểm đánh giá" của tôi lên phía trước tuple. Mã rõ ràng là sử dụng toàn bộ phần thứ hai cho quá trình phân loại, quá nặng và không cần thiết.


Đây là câu hỏi của tôi: Làm thế nào tôi có thể vui lòng sắp xếp chính xác hơn. Tôi không muốn sắp xếp theo toàn bộ phần thứ hai của từ điển của tôi: Tôi muốn nhắm mục tiêu chính xác mục đầu tiên.
Và lý tưởng là tôi muốn đặt giá trị này trở lại vị trí ban đầu, cụ thể là mục cuối cùng trong bộ dữ liệu thứ hai - và vẫn sắp xếp theo nó.


Tôi đã đọc lên trên và thử nghiệm với cú pháp của operator.itemgetter() nhưng chưa được quản lý để chỉ "lấy" các "mục đầu tiên của mặt hàng thứ hai của tôi". https://docs.python.org/3/library/operator.html?highlight=operator.itemgetter#operator.itemgetter

(lưu ý: Đây là phép sử dụng các bộ như khóa và giá trị, theo:
https://docs.python.org/3/tutorial/datastructures.html?highlight=dictionary và những người đang làm việc tốt cho dự án của tôi; câu hỏi này chỉ là sắp xếp về tốt hơn)


Đối với những người thích một nền nhỏ (bạn sẽ hét lên với tôi rằng tôi nên sử dụng một số phương pháp khác, nhưng tôi đang học về từ điển ngay bây giờ (là một trong những mục đích của dự án này)):

Tối ưu hóa này dành cho các nước đang phát triển, nơi thường không có sẵn giá trị tem nhất định hoặc bị giới hạn trong kho tại bất kỳ bưu điện cụ thể nào. Sau đó nó sẽ chạy trên điện thoại Android.

Chúng tôi đang gửi thư thường xuyên (có, thư). Tìm ra chính xác bưu chính cho mỗi điểm đến với các giá trị có sẵn và tìm giải pháp với các cổ phiếu thấp của một số giá trị nhất định là một quy trình không tầm thường, nếu bạn xem xét sáu bưu chính đích và hàng trăm thư khác nhau để gửi thư.

Có module khác mà giúp biến các giải pháp tối ưu về lý thuyết thành một cái gì đó thực sự có thể được mua trên bất kỳ ngày nào, bởi chiến lược thoại-hướng dẫn ...

Về từ điển của tôi trong câu hỏi này: Tôi lặp trên tất cả hợp lý (đủ cao để thực hiện bưu chính cần thiết và chỉ trả quá tối đa một phần tem) kết hợp các giá trị tem.

Sau đó, tôi tính giá trị "thành công", dựa trên số lượng tem cần thiết (ưu tiên), số lượng loại cần thiết (ưu tiên thấp hơn) (vì mua tem khác nhau cần thêm thời gian tại quầy) hình phạt cao cho việc thanh toán. Vì vậy, giá trị thấp nhất có nghĩa là thành công cao nhất.

Tôi thu thập tất cả "giải pháp" hợp lý trong từ điển trong đó bộ tem cần thiết đóng vai trò là khóa và một bộ dữ liệu kết quả khác tạo nên các giá trị. Nó được định nghĩa quá mức bởi vì con người cần đọc nó ở giai đoạn này trong dự án (để gỡ lỗi).

Nếu bạn tò mò và muốn đọc ví dụ (dòng đầu tiên):
Các colums là:

  • số tem 350 cent
  • số tem 200 cent
  • số tem 50 xu
  • số tem 25 xu
  • điểm đánh giá
  • tính bưu chính áp dụng
  • tổng số tem áp dụng
  • tổng số tem-loại
  • qua thanh toán theo đơn vị cent nếu có

Hoặc Bằng chữ: (Giả sử một dịch vụ bưu chính được cung cấp tem hiện tại là 350, 200, 50 và 25 xu), tôi có thể áp dụng bưu phí 75 xu bằng cách sử dụng 1x 50 xu và 1x 25 xu.Điều này mang lại cho tôi một đánh giá thành công của 22 (tốt nhất trong danh sách này), bưu chính là 75 cent, cần hai con tem của hai giá trị khác nhau và có 0 xu overpayment.

+0

Đây là câu hỏi bao giờ đầu tiên của tôi trên stackoverflow và tôi rất ấn tượng và rất biết ơn đối với phản hồi: Superfast và rất, rất hữu ích. Tôi chỉ quyết định chọn câu trả lời đầu tiên, bởi vì nó làm những gì tôi cần (Tôi đã thử nghiệm nó với dự án của tôi). Tôi đã chọn chủ yếu quá nhanh, không người dùng nào khác cần dành thời gian với nhiều câu trả lời hơn. Tôi hạnh phúc và có thể chuyển sang các mô-đun tiếp theo. Cảm ơn tất cả!! –

Trả lời

4

Bạn chỉ có thể sử dụng một chỉ số tăng gấp đôi, một cái gì đó như thế này nên làm việc:

MyDiccoSorted = sorted(MyDicco.items(), key=lambda s: s[1][2]) 

Chỉ cần đặt 2 cho bất kỳ chỉ mục nào của ID trong bộ dữ liệu.

+0

Cảm ơn, câu trả lời cực nhanh.Tôi thấy trong câu trả lời của bạn (và từ Rob) cú pháp key = lambda s: s [1] [4]. Giả sử rằng theo cách pythonian [4] sẽ cho tôi hạng mục thứ năm của các giá trị-tuple của tôi. Người đầu tiên làm gì? Nó là một tham chiếu đến mục thứ hai của khóa-tuple của tôi? Hoặc tôi có thể xin tra cứu cú pháp cho giải pháp key = lambda này ở đâu? –

+1

@MartinZaske Yup. Điều đó thực hiện trong mỗi phần tử 'MyDicco' và gán nó cho' s'. Sau đó, nó lấy phần tử đầu tiên của 's', và trả về phần tử thứ tư của nó. –

+0

Điều này do đó sẽ không nhìn vào các phím ở tất cả. Bạn có nghĩa là các giá trị, khi bạn viết "mỗi phần tử", phải không? Đó sẽ là một câu trả lời hoàn hảo ... –

4

Tôi thấy dễ sử dụng hơn lambda expressions hơn là để nhớ các hàm operator khác nhau.

Giả sử, cho thời điểm này, đó là điểm eval của bạn là mục thứ 3 của tuple giá trị của bạn (ví dụ (post, number, eval, types, over):

MyDiccoSorted = sorted(MyDicco.items(), key=lamba x:x[1][2]) 

Ngoài ra, bạn có thể tạo một hàm có tên để thực hiện công việc:

def myKey(x): return x[1][2] 
MyDiccoSorted = sorted(MyDicco.items(), key=myKey) 
2

Bạn có thể sử dụng biểu thức lambda thay vì operator.itemgetter() để lấy yếu tố chính xác cần sắp xếp. Giả sử bạn eval là mục đầu tiên trong tuple của values, nếu không sử dụng các chỉ số của phần tử chính xác mà bạn muốn trong x[1][0] .example -

MyDiccoSorted = sorted(MyDicco.items(), key=lambda x: x[1][0]) 

Làm thế nào các công trình này -

Một dict.items() lợi nhuận một cái gì đó tương tự như danh sách các bộ dữ liệu (mặc dù không chính xác như vậy trong Python 3.x), Ví dụ -

>>> d = {1:2,3:4} 
>>> d.items() 
dict_items([(1, 2), (3, 4)]) 

Bây giờ, trongHàm, đối số key chấp nhận đối tượng hàm (có thể là lambda hoặc operator.itemgetter() cũng trả về hàm hoặc bất kỳ hàm đơn giản nào), hàm mà bạn chuyển đến key phải chấp nhận một đối số, thành phần của danh sách đang được sắp xếp.

Sau đó, chức năng key được gọi với mỗi phần tử và bạn dự kiến ​​trả lại giá trị chính xác để sắp xếp danh sách. Ví dụ để giúp bạn hiểu điều này -

>>> def foo(x): 
...  print('x =',x) 
...  return x[1] 
... 
>>> sorted(d.items(),key=foo) 
x = (1, 2) 
x = (3, 4) 
[(1, 2), (3, 4)] 
1

thực hiện việc này có cần gì không?

sorted(MyDicco.items(), key=lambda x: x[1][0]) 
1
index_of_evaluation_score = 0 
MyDiccoSorted = sorted(MyDicco.items(), key=lambda key_value: key_value[1][index_of_evaluation_score]) 
1

Đặt đánh giá của bạn ghi lại vào cuối nơi bạn muốn nó, bạn có thể sử dụng như sau:

MyDicco = { 
    (0, 0, 1, 1): (75, 2, 2, 0, 22), 
    (0, 0, 0, 3): (75, 3, 1, 0, 31), 
    (0, 0, 2, 0): (100, 2, 1, 25, 2521), 
    (0, 1, 0, 0): (200, 1, 1, 125, 12511), 
    (1, 0, 0, 0): (350, 1, 1, 275, 27511)} 

MyDiccoSorted = sorted(MyDicco.items(), key=lambda x: x[1][4]) 

print MyDiccoSorted 

Giving:

[((0, 0, 1, 1), (75, 2, 2, 0, 22)), ((0, 0, 0, 3), (75, 3, 1, 0, 31)), ((0, 0, 2, 0), (100, 2, 1, 25, 2521)), ((0, 1, 0, 0), (200, 1, 1, 125, 12511)), ((1, 0, 0, 0), (350, 1, 1, 275, 27511))] 
Các vấn đề liên quan