Разница списка словарей - PullRequest
0 голосов
/ 03 апреля 2020

Я довольно много искал, но не нашел подобного вопроса.

У меня есть два списка словарей в следующем формате:

data1 = [
    {'id': 4, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
    {'id': 4, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
    {'id': 6, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
    {'id': 7, 'date_time': datetime.datetime(2020, 4, 3, 16, 14, 21)},
]

data2 = [
    {'id': 4, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
    {'id': 6, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
]

желаемый вывод:

final_data = [
    {'id': 4, 'date_time': datetime.datetime(2020, 4, 3, 12, 34, 40)},
    {'id': 7, 'date_time': datetime.datetime(2020, 4, 3, 16, 14, 21)},
]

Я хочу только словари, которые находятся в data1 а не в data2.

До сих пор, когда я нашел совпадение в двух циклах for, я выталкивал словарь из списка, но это не кажется мне хорошим подходом. Как я могу достичь желаемого результата?

Это не должно быть эффективным по времени, поскольку в каждом списке будет максимум десятки словарей


Текущая реализация:
counter_i = 0

for i in range(len(data1)):
    counter_j = 0
    for j in range(len(data2)):
        if data1[i-counter_i]['id'] == data2[j-counter_j]['id'] and data1[i-counter_i]['date_time'] == data2[j-counter_j]['date_time']
            data1.pop(i-counter_i)
            data2.pop(j-counter_j)
            counter_i += 1 
            counter_j += 1 
            break

Ответы [ 3 ]

2 голосов
/ 03 апреля 2020

Если производительность не является проблемой, почему бы и нет:

for d in data2:
    try:
        data1.remove(d)
    except ValueError:
        pass  

list.remove проверяет равенство объектов, а не идентичность, поэтому будет работать для кодов с одинаковыми ключами и значениями. Кроме того, list.remove удаляет только одно вхождение за раз.

1 голос
/ 03 апреля 2020

Ответ schwobaseggl, вероятно, является самым чистым решением (просто сделайте копию перед удалением, если вам нужно сохранить data1 нетронутой).

Но если вы хотите использовать разницу в множестве ... ну, в этом случае слова не являются хэшами, потому что их базовые данные могут измениться и привести к проблемам (по той же причине, по которой списки или наборы тоже не могут быть хешируемыми).

Однако вы можете получить все пары dict в frozenset для представления словаря (при условии значений словаря) являются хэш-schwobaseggl). Фрозенцеты могут быть хэшируемыми, так что вы можете добавлять их в набор и делать обычные различия. И восстановите словари в конце: D.

Я на самом деле не рекомендую делать это, но здесь мы go:

final_data = [
  dict(s)
  for s in set(
    frozenset(d.items()) for d in data1
  ).difference(
    frozenset(d.items()) for d in data2
  )
]
0 голосов
/ 03 апреля 2020

вы можете go любым способом:

Метод 1:

#using filter and lambda function
final_data = filter(lambda i: i not in data2, data1) 
final_data = list(final_data)

Метод 2:

# using list comprehension to perform task 
final_data = [i for i in data1 if i not in data2] 
...