Python에서 중복된 dict in 목록 제거
딕트 목록이 있는데 키와 값 쌍이 동일한 딕트를 삭제하고 싶습니다.
:[{'a': 123}, {'b': 123}, {'a': 123}]
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.[{'a': 123}, {'b': 123}]
또 다른 예는 다음과 같습니다.
:[{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.[{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]
이것을 시험해 보세요.
[dict(t) for t in {tuple(d.items()) for d in l}]
이 전략은 사전 목록을 튜플 목록에 사전 항목이 포함되어 있는 튜플 목록으로 변환하는 것입니다.할 수 .set
(여기서 일련의 이해를 사용하여 오래된 파이썬 대안은set(tuple(d.items()) for d in l)
그런 다음 다음 Tuples에서 사전을 다시 만듭니다.dict
.
여기서:
l
입니다.d
중 하나입니다.t
중 입니다.
편집: 주문을 유지하려면 위의 한 줄만 표시해도 다음 시간 이후로는 작동하지 않습니다.set
단몇 됩니다. : 、 몇 、 몇 、 몇 、 몇 、 몇 、 몇 、 몇 、 몇 、 몇 음 、 음 음 음 음 음 also also also also also also also also also 。
l = [{'a': 123, 'b': 1234},
{'a': 3222, 'b': 1234},
{'a': 123, 'b': 1234}]
seen = set()
new_l = []
for d in l:
t = tuple(d.items())
if t not in seen:
seen.add(t)
new_l.append(d)
print new_l
출력 예:
[{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]
주의: @alexis가 지적한 바와 같이 키와 값이 동일한 두 개의 사전이 동일한 태플이 되지 않을 수 있습니다.다른 키 추가/삭제 이력을 거치면 이 문제가 발생할 수 있습니다.있는 는, 「 「」의 정렬을 .d.items()
그의 제안대로.
목록 합산을 기반으로 한 또 다른 한 줄:
>>> d = [{'a': 123}, {'b': 123}, {'a': 123}]
>>> [i for n, i in enumerate(d) if i not in d[n + 1:]]
[{'b': 123}, {'a': 123}]
에서는 ★★★★★★★★★★★★★★를 사용할 수 있기 때문에,dict
첫 목록의 에 없는 이은 인덱스를 할 수 있습니다).n
, , , , , , , , , 을 사용합니다.enumerate
를 참조해 주세요.
서드파티 패키지를 사용해도 괜찮다면 다음을 사용할 수 있습니다.
>>> from iteration_utilities import unique_everseen
>>> l = [{'a': 123}, {'b': 123}, {'a': 123}]
>>> list(unique_everseen(l))
[{'a': 123}, {'b': 123}]
는 더 알고리즘예: 사전 등에한 항목을 할 수도 .O(n*m)
서 ''는n
이며, "는 " " " 입니다.m
내의 O(n)
이 모두 )를 할 수 .key
을 작성하기 인수(이 는 "에서 작동합니다).O(n)
를 참조해 주세요.
않고 의되는 다른 .frozenset
:
>>> list(unique_everseen(l, key=lambda item: frozenset(item.items())))
[{'a': 123}, {'b': 123}]
주의: 심플을 사용하면 안 됩니다.tuple
동일한 사전의 순서가 반드시 같지는 않기 때문에 접근법(정렬하지 않음)은 절대 순서가 아닌 삽입 순서가 보장되는 Python 3.7에서도 마찬가지입니다.
>>> d1 = {1: 1, 9: 9}
>>> d2 = {9: 9, 1: 1}
>>> d1 == d2
True
>>> tuple(d1.items()) == tuple(d2.items())
False
또한 키를 정렬할 수 없으면 태플 정렬도 작동하지 않을 수 있습니다.
>>> d3 = {1: 1, 'a': 'a'}
>>> tuple(sorted(d3.items()))
TypeError: '<' not supported between instances of 'str' and 'int'
벤치마크
이러한 접근방식의 퍼포먼스가 어떻게 비교되는지 확인하는 것이 도움이 될 수 있다고 생각하여 간단한 벤치마크를 실시했습니다.벤치마크 그래프는 중복이 없는 목록을 기반으로 한 시간 대 목록 크기입니다(임의로 선택한 경우 중복이 일부 또는 많이 추가되어도 런타임은 크게 변경되지 않습니다).로그 로그 플롯이므로 전체 범위가 포함됩니다.
절대 시간:
가장 빠른 접근 방식에 대한 타이밍:
사방에서 두 번째 접근은 여기서 가장 빠릅니다.그unique_everseen
가지고 접근하다key
기능은 2위이지만 질서를 유지하는 가장 빠른 접근 방식입니다.jcollado와 fourtheye의 다른 접근은 거의 같은 속도입니다.를 사용한 접근법unique_everseen
키가 없으면 Emmanuel과 Scorpil의 솔루션은 긴 목록에 비해 매우 느리고 훨씬 더 나쁘게 동작합니다.O(n*n)
O(n)
. stpks 어프로치json
그래O(n*n)
하지만 비슷한 것보다 훨씬 느리다.O(n)
근합니니다다
벤치마크를 재현하기 위한 코드:
from simple_benchmark import benchmark
import json
from collections import OrderedDict
from iteration_utilities import unique_everseen
def jcollado_1(l):
return [dict(t) for t in {tuple(d.items()) for d in l}]
def jcollado_2(l):
seen = set()
new_l = []
for d in l:
t = tuple(d.items())
if t not in seen:
seen.add(t)
new_l.append(d)
return new_l
def Emmanuel(d):
return [i for n, i in enumerate(d) if i not in d[n + 1:]]
def Scorpil(a):
b = []
for i in range(0, len(a)):
if a[i] not in a[i+1:]:
b.append(a[i])
def stpk(X):
set_of_jsons = {json.dumps(d, sort_keys=True) for d in X}
return [json.loads(t) for t in set_of_jsons]
def thefourtheye_1(data):
return OrderedDict((frozenset(item.items()),item) for item in data).values()
def thefourtheye_2(data):
return {frozenset(item.items()):item for item in data}.values()
def iu_1(l):
return list(unique_everseen(l))
def iu_2(l):
return list(unique_everseen(l, key=lambda inner_dict: frozenset(inner_dict.items())))
funcs = (jcollado_1, Emmanuel, stpk, Scorpil, thefourtheye_1, thefourtheye_2, iu_1, jcollado_2, iu_2)
arguments = {2**i: [{'a': j} for j in range(2**i)] for i in range(2, 12)}
b = benchmark(funcs, arguments, 'list size')
%matplotlib widget
import matplotlib as mpl
import matplotlib.pyplot as plt
plt.style.use('ggplot')
mpl.rcParams['figure.figsize'] = '8, 6'
b.plot(relative_to=thefourtheye_2)
완전성을 위해 중복된 목록만 포함하는 타이밍을 다음에 나타냅니다.
# this is the only change for the benchmark
arguments = {2**i: [{'a': 1} for j in range(2**i)] for i in range(2, 12)}
은 크게 unique_everseen
없이key
이 경우 가장 빠른 해결책입니다. 이것은 캐시 의 값을 그 것은 다르기 때문입니다.O(n*m)
에, 「1」로 합니다.O(n)
면책사항:나는 의 작가이다.iteration_utilities
.
역직렬화된 JSON 개체와 같은 중첩된 사전에서 작업하는 경우 다른 응답은 작동하지 않습니다.이 경우 다음을 사용할 수 있습니다.
import json
set_of_jsons = {json.dumps(d, sort_keys=True) for d in X}
X = [json.loads(t) for t in set_of_jsons]
워크플로우에서 Panda를 사용하는 경우 한 가지 옵션은 사전 목록을 직접 제공하는 것입니다.pd.DataFrame
컨스트럭터그런 다음 및 방법을 사용하여 필요한 결과를 얻습니다.
import pandas as pd
d = [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]
d_unique = pd.DataFrame(d).drop_duplicates().to_dict('records')
print(d_unique)
[{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]
오래된 스타일의 루프가 여전히 유용할 수 있습니다.이 코드는 jcollado 코드보다 조금 길지만 읽기 매우 쉽습니다.
a = [{'a': 123}, {'b': 123}, {'a': 123}]
b = []
for i in range(len(a)):
if a[i] not in a[i+1:]:
b.append(a[i])
주문을 보존하려면 다음 작업을 수행합니다.
from collections import OrderedDict
print OrderedDict((frozenset(item.items()),item) for item in data).values()
# [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]
순서가 중요하지 않으면 다음 작업을 수행할 수 있습니다.
print {frozenset(item.items()):item for item in data}.values()
# [{'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]
일반적인 답은 아니지만, 다음과 같은 키별로 목록이 정렬될 경우:
l=[{'a': {'b': 31}, 't': 1},
{'a': {'b': 31}, 't': 1},
{'a': {'b': 145}, 't': 2},
{'a': {'b': 25231}, 't': 2},
{'a': {'b': 25231}, 't': 2},
{'a': {'b': 25231}, 't': 2},
{'a': {'b': 112}, 't': 3}]
솔루션은 다음과 같이 심플합니다.
import itertools
result = [a[0] for a in itertools.groupby(l)]
결과:
[{'a': {'b': 31}, 't': 1},
{'a': {'b': 145}, 't': 2},
{'a': {'b': 25231}, 't': 2},
{'a': {'b': 112}, 't': 3}]
중첩된 사전과 함께 작동하며 순서를 유지합니다.
세트를 사용할 수 있지만 dits를 해시 가능한 유형으로 변환해야 합니다.
seq = [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]
unique = set()
for d in seq:
t = tuple(d.iteritems())
unique.add(t)
유니크한 기능
set([(('a', 3222), ('b', 1234)), (('a', 123), ('b', 1234))])
받아쓰기를 되돌리려면:
[dict(x) for x in unique]
사전은 해시할 수 없으므로 목록의 각 항목을 문자열로 변환하는 것이 가장 쉬운 방법입니다.그런 다음 집합을 사용하여 중복 항목을 제거할 수 있습니다.
list_org = [{'a': 123}, {'b': 123}, {'a': 123}]
list_org_updated = [ str(item) for item in list_org]
print(list_org_updated)
["{'a': 123}", "{'b': 123}", "{'a': 123}"]
unique_set = set(list_org_updated)
print(unique_set)
{"{'b': 123}", "{'a': 123}"}
세트를 사용할 수 있지만 목록을 원할 경우 다음을 추가합니다.
import ast
unique_list = [ast.literal_eval(item) for item in unique_set]
print(unique_list)
[{'b': 123}, {'a': 123}]
다음은 목록 이해가 이중화된 간단한 한 줄 솔루션입니다(@Emanuel의 솔루션에 기반).
를 들어, 「」라고 하는 키)를합니다.a
가 dict와 하는 것이 각 dict를
[i for n, i in enumerate(list_of_dicts) if i.get(primary_key) not in [y.get(primary_key) for y in list_of_dicts[n + 1:]]]
OP가 요구했던 것은 아니지만, 그것이 나를 이 상황에 이르게 한 이유이기 때문에, 나는 최종적인 솔루션을 투고하려고 생각했다.
짧지는 않지만 읽기 쉽다:
list_of_data = [{'a': 123}, {'b': 123}, {'a': 123}]
list_of_data_uniq = []
for data in list_of_data:
if data not in list_of_data_uniq:
list_of_data_uniq.append(data)
이제 목록, 목록list_of_data_uniq
이치노
사용자 지정 키로 중복 제거:
def remove_duplications(arr, key):
return list({key(x): x for x in arr}.values())
중복된 값과 키를 검색하는 많은 좋은 예를 다음에 제시하겠습니다.목록에 있는 전체 사전 중복 데이터를 필터링하는 방법은 다음과 같습니다.원본 데이터가 정확히 포맷된 사전으로 구성되어 있고 중복된 데이터를 찾는 경우 dupKeys = []를 사용합니다.그렇지 않으면 dupKeys =를 중복되지 않을 데이터의 키 이름으로 설정합니다(1 ~ n개 키).우아하지만 기능성과 유연성이 뛰어납니다.
import binascii
collected_sensor_data = [{"sensor_id":"nw-180","data":"XXXXXXX"},
{"sensor_id":"nw-163","data":"ZYZYZYY"},
{"sensor_id":"nw-180","data":"XXXXXXX"},
{"sensor_id":"nw-97", "data":"QQQQQZZ"}]
dupKeys = ["sensor_id", "data"]
def RemoveDuplicateDictData(collected_sensor_data, dupKeys):
checkCRCs = []
final_sensor_data = []
if dupKeys == []:
for sensor_read in collected_sensor_data:
ck1 = binascii.crc32(str(sensor_read).encode('utf8'))
if not ck1 in checkCRCs:
final_sensor_data.append(sensor_read)
checkCRCs.append(ck1)
else:
for sensor_read in collected_sensor_data:
tmp = ""
for k in dupKeys:
tmp += str(sensor_read[k])
ck1 = binascii.crc32(tmp.encode('utf8'))
if not ck1 in checkCRCs:
final_sensor_data.append(sensor_read)
checkCRCs.append(ck1)
return final_sensor_data
final_sensor_data = [{"sensor_id":"nw-180","data":"XXXXXXX"},
{"sensor_id":"nw-163","data":"ZYZYZYY"},
{"sensor_id":"nw-97", "data":"QQQQQZZ"}]
확장성과 뛰어난 퍼포먼스에 관심이 없다면 간단한 기능:
# Filters dicts with the same value in unique_key
# in: [{'k1': 1}, {'k1': 33}, {'k1': 1}]
# out: [{'k1': 1}, {'k1': 33}]
def remove_dup_dicts(list_of_dicts: list, unique_key) -> list:
unique_values = list()
unique_dicts = list()
for obj in list_of_dicts:
val = obj.get(unique_key)
if val not in unique_values:
unique_values.append(val)
unique_dicts.append(obj)
return unique_dicts
언급URL : https://stackoverflow.com/questions/9427163/remove-duplicate-dict-in-list-in-python
'source' 카테고리의 다른 글
ubuntu 12.04의 nodejs 대 노드 (0) | 2023.02.06 |
---|---|
CASE 및 GROUP BY 결과에서 새 열 만들기 (0) | 2023.02.06 |
ballerina.io SQL LIKE 스테이트먼트 (0) | 2023.02.06 |
Java 8: Java.util.function의 TriFunction(및 kin)은 어디에 있습니까?아니면 대체방법이 뭐죠? (0) | 2023.02.06 |
비단뱀의 람다로 if를 하는 방법이 있나요? (0) | 2023.02.06 |