2012-02-03 26 views
11
khác

Tôi đang làm việc với một list của dict đối tượng trông như thế này (theo thứ tự của các đối tượng khác):Cho một danh sách các từ điển, làm thế nào tôi có thể loại bỏ các bản sao của một chìa khóa, và sắp xếp theo

[ 
    {'name': 'Foo', 'score': 1}, 
    {'name': 'Bar', 'score': 2}, 
    {'name': 'Foo', 'score': 3}, 
    {'name': 'Bar', 'score': 3}, 
    {'name': 'Foo', 'score': 2}, 
    {'name': 'Baz', 'score': 2}, 
    {'name': 'Baz', 'score': 1}, 
    {'name': 'Bar', 'score': 1} 
] 

Điều tôi muốn làm là xóa tên trùng lặp, chỉ giữ một tên của mỗi tên có số cao nhất là 'score'. Kết quả từ danh sách trên sẽ là:

[ 
    {'name': 'Baz', 'score': 2}, 
    {'name': 'Foo', 'score': 3}, 
    {'name': 'Bar', 'score': 3} 
] 

Tôi không chắc chắn mà mẫu để sử dụng ở đây (ngoài một vòng dường như ngu ngốc mà giữ kiểm tra nếu hiện tại dict 's 'name' có trong danh sách đã và sau đó . kiểm tra nếu nó 'score' cao hơn 'score'

+3

Đi với vòng lặp, nó đơn giản và rõ ràng. –

+3

Đơn giản và rõ ràng và dễ đọc trong sáu tháng khi bạn cần thay đổi nó "hơi" –

+2

+1 Có điều gì đó kỳ diệu về câu hỏi này ở chỗ nó đã đưa ra một loạt các câu trả lời đa dạng và thú vị. Nó là hấp dẫn bao nhiêu giải pháp hoàn toàn khác nhau vấn đề này có. Tôi coi đây là một yêu thích vì bộ câu trả lời phong phú (cũng có thể trả lời mọi câu trả lời có giải pháp sáng tạo hoặc thú vị). –

Trả lời

15

một cách hiện của một người để làm điều đó là:

data = collections.defaultdict(list) 
for i in my_list: 
    data[i['name']].append(i['score']) 
output = [{'name': i, 'score': max(j)} for i,j in data.items()] 

nên đầu ra sẽ là:

[{'score': 2, 'name': 'Baz'}, 
{'score': 3, 'name': 'Foo'}, 
{'score': 3, 'name': 'Bar'}] 
+2

Tôi đã học được rất nhiều về Python từ điều này, nhờ – mVChr

3

Sắp xếp là một nửa trận chiến.

import itertools 
import operator 

scores = [ 
    {'name': 'Foo', 'score': 1}, 
    {'name': 'Bar', 'score': 2}, 
    {'name': 'Foo', 'score': 3}, 
    {'name': 'Bar', 'score': 3}, 
    {'name': 'Foo', 'score': 2}, 
    {'name': 'Baz', 'score': 2}, 
    {'name': 'Baz', 'score': 1}, 
    {'name': 'Bar', 'score': 1} 
] 

result = [] 
sl = sorted(scores, key=operator.itemgetter('name', 'score'), 
    reverse=True) 
name = object() 
for el in sl: 
    if el['name'] == name: 
    continue 
    name = el['name'] 
    result.append(el) 
print result 
+1

+1 Câu trả lời này là câu trả lời duy nhất không biến đổi tập dữ liệu. Có vẻ phù hợp và từ điển có thể có thêm các mặt hàng nếu OP muốn. – JBernardo

+1

+1 cho "Phân loại là một nửa trận chiến." –

+0

Mục đích của việc sử dụng' object() 'ở đây là gì? – fletom

2

Đây là cách đơn giản nhất tôi có thể nghĩ:

names = set(d['name'] for d in my_dicts) 
new_dicts = [] 
for name in names: 
    d = dict(name=name) 
    d['score'] = max(d['score'] for d in my_dicts if d['name']==name) 
    new_dicts.append(d) 

#new_dicts 
[{'score': 2, 'name': 'Baz'}, 
{'score': 3, 'name': 'Foo'}, 
{'score': 3, 'name': 'Bar'}] 

Cá nhân, tôi không muốn import module khi vấn đề là quá nhỏ.

2

Trong trường hợp bạn đã không nghe nói về nhóm bởi, đây là sử dụng tốt đẹp của nó:

from itertools import groupby 

data=[ 
    {'name': 'Foo', 'score': 1}, 
    {'name': 'Bar', 'score': 2}, 
    {'name': 'Foo', 'score': 3}, 
    {'name': 'Bar', 'score': 3}, 
    {'name': 'Foo', 'score': 2}, 
    {'name': 'Baz', 'score': 2}, 
    {'name': 'Baz', 'score': 1}, 
    {'name': 'Bar', 'score': 1} 
] 

keyfunc=lambda d:d['name'] 
data.sort(key=keyfunc) 

ans=[] 
for k, g in groupby(data, keyfunc): 
    ans.append({k:max((d['score'] for d in g))}) 
print ans 

>>> 
[{'Bar': 3}, {'Baz': 2}, {'Foo': 3}] 
11

Không cần cho defaultdicts hoặc bộ ở đây. Bạn chỉ có thể sử dụng dicts và danh sách đơn giản.

Tóm tắt số điểm chạy nhất trong một cuốn từ điển và chuyển đổi kết quả trở lại vào một danh sách:

>>> s = [ 
    {'name': 'Foo', 'score': 1}, 
    {'name': 'Bar', 'score': 2}, 
    {'name': 'Foo', 'score': 3}, 
    {'name': 'Bar', 'score': 3}, 
    {'name': 'Foo', 'score': 2}, 
    {'name': 'Baz', 'score': 2}, 
    {'name': 'Baz', 'score': 1}, 
    {'name': 'Bar', 'score': 1} 
] 
>>> d = {} 
>>> for entry in s: 
     name, score = entry['name'], entry['score'] 
     d[name] = max(d.get(name, 0), score) 

>>> [{'name': name, 'score': score} for name, score in d.items()] 
[{'score': 2, 'name': 'Baz'}, {'score': 3, 'name': 'Foo'}, {'score': 3, 'name': 'Bar'}] 
+1

Giải pháp này sẽ thanh lịch nhất nếu chúng ta sử dụng cấu trúc dữ liệu như '{'Foo': 3}' thay vì '[{'name': 'Foo', 'score': 3}]'. Tôi sẽ cho rằng – fletom

+1

Đây là giải pháp yêu thích của tôi.Điều duy nhất tôi sẽ thay đổi là d.get (tên, 0) thành d.get (tên, điểm số), điều này cũng cho phép điểm số âm. –

2

Tôi nghĩ rằng tôi có thể đưa ra một one-liner ở đây:

result = dict((x['name'],x) for x in sorted(data,key=lambda x: x['score'])).values() 
+0

Rất đẹp, phần này có thể đọc được một lớp lót. –

5

Just for vui vẻ, đây là một cách tiếp cận hoàn toàn chức năng:

>>> map(dict, dict(sorted(map(sorted, map(dict.items, s)))).items()) 
[{'score': 3, 'name': 'Bar'}, {'score': 2, 'name': 'Baz'}, {'score': 3, 'name': 'Foo'}] 
Các vấn đề liên quan