Удаление дубликатов объектов JSON из списка в python

у меня есть список dict, где определенное значение повторяется несколько раз, и я хотел бы удалить дубликаты значений.

мой список:

te = [
      {
        "Name": "Bala",
        "phone": "None"
      },
      {
        "Name": "Bala",
        "phone": "None"
      },
      {
        "Name": "Bala",
        "phone": "None"
      },
      {
        "Name": "Bala",
        "phone": "None"
      }
    ]

функция для удаления повторяющихся значений:

def removeduplicate(it):
    seen = set()
    for x in it:
        if x not in seen:
            yield x
            seen.add(x)

когда я вызываю эту функцию, я получаю generator object.

<generator object removeduplicate at 0x0170B6E8>

когда я пытаюсь перебрать генератор я вам TypeError: unhashable type: 'dict'

есть ли способ удалить повторяющиеся значения или выполнить итерацию по генератору

3 ответов


вы можете легко удалить дубликаты ключей по пониманию словаря, так как словарь не позволяет дублировать ключи, как показано ниже -

te = [
      {
        "Name": "Bala",
        "phone": "None"
      },
      {
        "Name": "Bala",
        "phone": "None"
      },
      {
        "Name": "Bala",
        "phone": "None"
      },
      {
        "Name": "Bala",
        "phone": "None"
      },
      {
          "Name": "Bala1",
          "phone": "None"
      }      
    ]

unique = { each['Name'] : each for each in te }.values()

print unique

выход-

[{'phone': 'None', 'Name': 'Bala1'}, {'phone': 'None', 'Name': 'Bala'}]

потому что вы не можете добавить dict to set. От этот вопрос:

вы пытаетесь использовать dict как ключ к другой dict или set. Что не работает, потому что ключи должны быть hashable.

как правило, являются hashable только неизменяемые объекты (строки, целые числа, поплавки, frozensets, кортежи immutables) (хотя исключения возможны).

>>> foo = dict()
>>> bar = set()
>>> bar.add(foo)
Traceback (most recent call last):
  File "<input>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>> 

вместо этого, вы уже используя if x not in seen, поэтому просто используйте список:

>>> te = [
...       {
...         "Name": "Bala",
...         "phone": "None"
...       },
...       {
...         "Name": "Bala",
...         "phone": "None"
...       },
...       {
...         "Name": "Bala",
...         "phone": "None"
...       },
...       {
...         "Name": "Bala",
...         "phone": "None"
...       }
...     ]

>>> def removeduplicate(it):
...     seen = []
...     for x in it:
...         if x not in seen:
...             yield x
...             seen.append(x)

>>> removeduplicate(te)
<generator object removeduplicate at 0x7f3578c71ca8>

>>> list(removeduplicate(te))
[{'phone': 'None', 'Name': 'Bala'}]
>>> 

вы все еще можете использовать set для обнаружения дубликатов вам просто нужно преобразовать словарь в нечто хэшируемое, такое как tuple. Ваши словари могут быть преобразованы в кортежи с помощью tuple(d.items()) здесь d словарь. Применяя это к вашей функции генератора:

def removeduplicate(it):
    seen = set()
    for x in it:
        t = tuple(x.items())
        if t not in seen:
            yield x
            seen.add(t)

>>> for d in removeduplicate(te):
...    print(d)
{'phone': 'None', 'Name': 'Bala'}

>>> te.append({'Name': 'Bala', 'phone': '1234567890'})
>>> te.append({'Name': 'Someone', 'phone': '1234567890'})

>>> for d in removeduplicate(te):
...    print(d)
{'phone': 'None', 'Name': 'Bala'}
{'phone': '1234567890', 'Name': 'Bala'}
{'phone': '1234567890', 'Name': 'Someone'}

это обеспечивает более быстрый поиск (avg. O (1)) чем "видел" list (O (n)). Стоит ли дополнительно вычислять преобразование каждого Дикта в кортеж, зависит от количества словарей что у вас есть и сколько дубликатов. Если есть много дубликатов, "видел" list будет расти довольно большой, и тестирование того, был ли уже замечен dict, может стать дорогостоящей операцией. Это может оправдать преобразование кортежа - вам придется протестировать / профилировать его.