Eu tenho uma lista de dictos e gostaria de removê-los com pares de chave e valor idênticos.
Para esta lista: [{'a': 123}, {'b': 123}, {'a': 123}]
Queria devolver isto: [{'a': 123}, {'b': 123}]
Outro exemplo:
Para esta lista: [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]
Queria devolver isto: [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]
python
list
dictionary
Brenden
fonte
fonte
set()
Respostas:
Tente o seguinte:
A estratégia é converter a lista de dicionários em uma lista de tuplas onde as tuplas contêm os itens do dicionário. Como as tuplas podem ser hash, você pode remover duplicatas usando
set
(usando uma compreensão de conjunto aqui, seria a alternativa mais antiga do pythonset(tuple(d.items()) for d in l)
) e, depois disso, recrie os dicionários das tuplas comdict
.Onde:
l
é a lista originald
é um dos dicionários da listat
é uma das tuplas criadas a partir de um dicionárioEditar: se você deseja preservar os pedidos, a linha única acima não funcionará, pois
set
não fará isso. No entanto, com algumas linhas de código, você também pode fazer isso:Exemplo de saída:
Nota: Conforme apontado pelo @alexis, pode acontecer que dois dicionários com as mesmas chaves e valores não resultem na mesma tupla. Isso pode acontecer se eles passarem por um histórico diferente de adicionar / remover chaves. Se esse for o caso do seu problema, considere a classificação
d.items()
como ele sugere.fonte
d.items()
não é garantido o retorno de elementos em uma ordem específica. Você deve fazer issotuple(sorted(d.items()))
para garantir que não obtenha tuplas diferentes para os mesmos pares de valores-chave.json
módulo como eu fizOutra linha de base baseada na compreensão da lista:
Aqui, como podemos usar a
dict
comparação, mantemos apenas os elementos que não estão no restante da lista inicial (essa noção é acessível apenas através do índicen
, daí o uso deenumerate
).fonte
if i not in d[n + 1:]
itera sobre a lista inteira de dicts (den
, mas que apenas metades do número total de operações) e que está fazendo essa verificação para cada elemento no seu dicionário de modo que este este código é O (n ^ 2) complexidade de tempoOutras respostas não funcionariam se você estiver operando em dicionários aninhados, como objetos JSON desserializados. Para este caso, você pode usar:
fonte
Se o uso de um pacote de terceiros estiver correto, você poderá usar
iteration_utilities.unique_everseen
:Ele preserva a ordem da lista original e ut também pode manipular itens laváveis como dicionários, recorrendo a um algoritmo mais lento (
O(n*m)
onden
estão os elementos na lista original em
os elementos únicos na lista originalO(n)
). No caso de chaves e valores serem hashable, você pode usar okey
argumento dessa função para criar itens hashable para o "teste de exclusividade" (para que funcioneO(n)
).No caso de um dicionário (que compara independentemente da ordem), você precisa mapeá-lo para outra estrutura de dados que se compara assim, por exemplo
frozenset
:Observe que você não deve usar uma
tuple
abordagem simples (sem classificação) porque dicionários iguais não necessariamente têm a mesma ordem (mesmo no Python 3.7 onde a ordem de inserção - não a ordem absoluta - é garantida):E mesmo classificar a tupla pode não funcionar se as chaves não forem classificáveis:
Referência
Eu pensei que seria útil ver como o desempenho dessas abordagens se compara, então fiz uma pequena referência. Os gráficos de referência são o tempo versus o tamanho da lista com base em uma lista que não contém duplicatas (que foi escolhida arbitrariamente, o tempo de execução não muda significativamente se eu adicionar algumas ou muitas duplicatas). É um gráfico de log-log, para que toda a gama seja coberta.
Os tempos absolutos:
Os tempos relativos à abordagem mais rápida:
A segunda abordagem do quarto olho é mais rápida aqui. A
unique_everseen
abordagem com akey
função está em segundo lugar, no entanto, é a abordagem mais rápida que preserva a ordem. As outras abordagens de jcollado e thefourtheye são quase tão rápidas. A abordagem usandounique_everseen
sem chave e as soluções de Emmanuel e Scorpil são muito lentas para listas mais longas e se comportam muito pior emO(n*n)
vez deO(n)
. A abordagem do stpkjson
não é,O(n*n)
mas é muito mais lenta que asO(n)
abordagens semelhantes .O código para reproduzir os benchmarks:
Para completar, é o momento para uma lista que contém apenas duplicatas:
Os tempos não mudam significativamente, exceto
unique_everseen
semkey
função, que neste caso é a solução mais rápida. No entanto, esse é apenas o melhor caso (não representativo) para essa função com valores laváveis, porque o tempo de execução depende da quantidade de valores exclusivos da lista:O(n*m)
que neste caso é apenas 1 e, portanto, é executadaO(n)
.Disclaimer: Eu sou o autor de
iteration_utilities
.fonte
Às vezes, loops de estilo antigo ainda são úteis. Este código é um pouco mais longo que o do jcollado, mas é muito fácil de ler:
fonte
0
norange(0, len(a))
não é necessário.Se você deseja preservar a Ordem, pode fazer
Se o pedido não importa, você pode fazer
fonte
dict_values
saída não serializável em vez de uma lista. Você precisa colocar a coisa toda em uma lista novamente.list(frozen.....)
Se você estiver usando o Pandas no seu fluxo de trabalho, uma opção é alimentar uma lista de dicionários diretamente ao
pd.DataFrame
construtor. Em seguida, usedrop_duplicates
eto_dict
métodos para o resultado desejado.fonte
Não é uma resposta universal , mas se sua lista for classificada por alguma chave, desta forma:
então a solução é tão simples quanto:
Resultado:
Funciona com dicionários aninhados e (obviamente) preserva a ordem.
fonte
Você pode usar um conjunto, mas precisa transformar os dict em um tipo lavável.
Único agora é igual
Para recuperar os ditados:
fonte
d.iteritems()
não é garantida; portanto, você poderá acabar com 'duplicatas'unique
.Aqui está uma solução rápida de uma linha com uma compreensão de lista duplamente aninhada (com base na solução de @Emmanuel).
Isso usa uma única chave (por exemplo
a
) em cada ditado como chave primária, em vez de verificar se o ditado inteiro correspondeNão é o que o OP pediu, mas foi o que me levou a esse segmento, então pensei em publicar a solução com a qual acabei
fonte
Não é tão curto, mas fácil de ler:
Agora, a lista
list_of_data_uniq
terá ditados únicos.fonte