简体   繁体   English

Python - 在字典列表中查找重复项并对其进行分组

[英]Python - Find duplicates in a list of dictionaries and group them

i'm not a programmer and also new to python, i have a list of dicts coming from a json file: 我不是程序员,也不是python的新手,我有一个来自json文件的dicts列表:

# JSON file (film.json)
[{"year": ["1999"], "director": ["Wachowski"], "film": ["The Matrix"], "price": ["19,00"]},
{"year": ["1994"], "director": ["Tarantino"], "film": ["Pulp Fiction"], "price": ["20,00"]},
{"year": ["2003"], "director": ["Tarantino"], "film": ["Kill Bill vol.1"], "price": ["10,00"]},
{"year": ["2003"], "director": ["Wachowski"], "film": ["The Matrix Reloaded"], "price": ["9,99"]},
{"year": ["1994"], "director": ["Tarantino"], "film": ["Pulp Fyction"], "price": ["15,00"]},
{"year": ["1994"], "director": ["E. de Souza"], "film": ["Street Fighter"], "price": ["2,00"]},
{"year": ["1999"], "director": ["Wachowski"], "film": ["The Matrix"], "price": ["20,00"]},
{"year": ["1982"], "director": ["Ridley Scott"], "film": ["Blade Runner"], "price": ["19,99"]}]

i can import json file with: 我可以导入json文件:

import json
json_file = open('film.json')
f = json.load(json_file)

but after that i'm not able to find occurrences in f and separate them in groups by film title. 但在那之后,我无法在f找到事件,并按电影片名分组。 This is what i'm looking for to achieve: 这就是我想要实现的目标:

## result grouped by 'film'
#group 1
{"year": ["1999"], "director": ["Wachowski"], "film": ["The Matrix"], "price": ["19,00"]}
{"year": ["1999"], "director": ["Wachowski"], "film": ["The Matrix"], "price": ["20,00"]}
#group 2
{"year": ["1994"], "director": ["Tarantino"], "film": ["Pulp Fiction"], "price": ["20,00"]}
{"year": ["1994"], "director": ["Tarantino"], "film": ["Pulp Fyction"], "price": ["15,00"]}
#group X
 ...

Or better: 或更好:

new_dict = { 'group1':[[],[],...] , 'group2':[[],[],...] , 'groupX':[...] }

At the moment i'm testing with nested for but without luck.. 目前我正在测试嵌套for但没有运气..

Thank you. 谢谢。

note: "pulp fyction" is a wanted mistake for future implementation with fuzzy string matching, for now i need only a 'duplicates grouper' 注意:“纸浆fyction”是未来实现的模糊字符串匹配的错误,现在我只需要一个'重复的石斑鱼'

note2: with python 2.x note2:使用python 2.x.

Because your data is not sorted, use a collections.defaultdict() object to materialize a list for new keys, then key by film title: 由于您的数据未排序,请使用collections.defaultdict()对象来实现新键的列表,然后按电影标题键入:

from collections import defaultdict

grouped = defaultdict(list)

for film in f:
    grouped[film['film'][0]].append(film)

The film['film'][0] value is used to group the films. film['film'][0]值用于分组电影。 You would have to create a canonical version of that key if you wanted to use more sophisticated title grouping. 如果您想使用更复杂的标题分组,则必须创建该密钥的规范版本。

Demo: 演示:

>>> from collections import defaultdict
>>> import json
>>> with open('film.json') as film_file:
...     f = json.load(film_file)
... 
>>> grouped = defaultdict(list)
>>> for film in f:
...     grouped[film['film'][0]].append(film)
... 
>>> grouped
defaultdict(<type 'list'>, {u'Street Fighter': [{u'director': [u'E. de Souza'], u'price': [u'2,00'], u'film': [u'Street Fighter'], u'year': [u'1994']}], u'Pulp Fiction': [{u'director': [u'Tarantino'], u'price': [u'20,00'], u'film': [u'Pulp Fiction'], u'year': [u'1994']}], u'Pulp Fyction': [{u'director': [u'Tarantino'], u'price': [u'15,00'], u'film': [u'Pulp Fyction'], u'year': [u'1994']}], u'The Matrix': [{u'director': [u'Wachowski'], u'price': [u'19,00'], u'film': [u'The Matrix'], u'year': [u'1999']}, {u'director': [u'Wachowski'], u'price': [u'20,00'], u'film': [u'The Matrix'], u'year': [u'1999']}], u'Blade Runner': [{u'director': [u'Ridley Scott'], u'price': [u'19,99'], u'film': [u'Blade Runner'], u'year': [u'1982']}], u'Kill Bill vol.1': [{u'director': [u'Tarantino'], u'price': [u'10,00'], u'film': [u'Kill Bill vol.1'], u'year': [u'2003']}], u'The Matrix Reloaded': [{u'director': [u'Wachowski'], u'price': [u'9,99'], u'film': [u'The Matrix Reloaded'], u'year': [u'2003']}]})
>>> from pprint import pprint
>>> pprint(dict(grouped))
{u'Blade Runner': [{u'director': [u'Ridley Scott'],
                    u'film': [u'Blade Runner'],
                    u'price': [u'19,99'],
                    u'year': [u'1982']}],
 u'Kill Bill vol.1': [{u'director': [u'Tarantino'],
                       u'film': [u'Kill Bill vol.1'],
                       u'price': [u'10,00'],
                       u'year': [u'2003']}],
 u'Pulp Fiction': [{u'director': [u'Tarantino'],
                    u'film': [u'Pulp Fiction'],
                    u'price': [u'20,00'],
                    u'year': [u'1994']}],
 u'Pulp Fyction': [{u'director': [u'Tarantino'],
                    u'film': [u'Pulp Fyction'],
                    u'price': [u'15,00'],
                    u'year': [u'1994']}],
 u'Street Fighter': [{u'director': [u'E. de Souza'],
                      u'film': [u'Street Fighter'],
                      u'price': [u'2,00'],
                      u'year': [u'1994']}],
 u'The Matrix': [{u'director': [u'Wachowski'],
                  u'film': [u'The Matrix'],
                  u'price': [u'19,00'],
                  u'year': [u'1999']},
                 {u'director': [u'Wachowski'],
                  u'film': [u'The Matrix'],
                  u'price': [u'20,00'],
                  u'year': [u'1999']}],
 u'The Matrix Reloaded': [{u'director': [u'Wachowski'],
                           u'film': [u'The Matrix Reloaded'],
                           u'price': [u'9,99'],
                           u'year': [u'2003']}]}

Using SoundEx to group films would be as simple as: 使用SoundEx对电影进行分组将非常简单:

from itertools import groupby, islice, ifilter

_codes = ('bfpv', 'cgjkqsxz', 'dt', 'l', 'mn', 'r')
_sounds = {c: str(i) for i, code in enumerate(_codes, 1) for c in code}
_sounds.update(dict.fromkeys('aeiouy'))
def soundex(word, _sounds=_sounds):
    grouped = groupby(_sounds[c] for c in word.lower() if c in _sounds)
    if _sounds.get(word[0].lower()):
        next(grouped)  # remove first group.
    sdx = ''.join([k for k, g in islice((g for g in grouped if g[0]), 3)])
    return word[0].upper() + format(sdx, '<03')

grouped_by_soundex = defaultdict(list)
for film in f:
    grouped_by_soundex[soundex(film['film'][0])].append(film)

resulting in: 导致:

>>> pprint(dict(grouped_by_soundex))
{u'B436': [{u'director': [u'Ridley Scott'],
            u'film': [u'Blade Runner'],
            u'price': [u'19,99'],
            u'year': [u'1982']}],
 u'K414': [{u'director': [u'Tarantino'],
            u'film': [u'Kill Bill vol.1'],
            u'price': [u'10,00'],
            u'year': [u'2003']}],
 u'P412': [{u'director': [u'Tarantino'],
            u'film': [u'Pulp Fiction'],
            u'price': [u'20,00'],
            u'year': [u'1994']},
           {u'director': [u'Tarantino'],
            u'film': [u'Pulp Fyction'],
            u'price': [u'15,00'],
            u'year': [u'1994']}],
 u'S363': [{u'director': [u'E. de Souza'],
            u'film': [u'Street Fighter'],
            u'price': [u'2,00'],
            u'year': [u'1994']}],
 u'T536': [{u'director': [u'Wachowski'],
            u'film': [u'The Matrix'],
            u'price': [u'19,00'],
            u'year': [u'1999']},
           {u'director': [u'Wachowski'],
            u'film': [u'The Matrix Reloaded'],
            u'price': [u'9,99'],
            u'year': [u'2003']},
           {u'director': [u'Wachowski'],
            u'film': [u'The Matrix'],
            u'price': [u'20,00'],
            u'year': [u'1999']}]}

If it was a one off and I was in a hurry I would do it like this. 如果它是一次性的,我很匆忙,我会这样做。 Assuming for this example that your list of dictionaries is lod, and that the film title will only ever be a list with one item 假设这个例子你的词典列表是lod,并且电影标题将只是一个带有一个项目的列表

new_dict = {k:[d for d in lod if d.get('film')[0] == k] for k in set(d.get('film')[0] for d in l)}

To make it more readable, and explain what it is doing, the same thing broken out, again the list of dictionaries is lod: 为了使它更具可读性,并解释它正在做什么,同样的事情被打破了,再次列出的词典是lod:

#get all the unique film names
# note: the [0] is because its a list for the title, and set doesn't work with lists,
#so we're just taking the first one for this example. 
films = set(d.get('film')[0] for d in lod)


#create a dictionary
new_dict = {}

#iterate over the unique film names
for k in films:
    #make a list of all the films that match the name we're on
    filmswiththisname = [d for d in lod if d.get('film')[0] == k]
    #add the list of films to the new dictionary with the film name as the key.
    new_dict[k] = filmswiththisname

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM