Soru Python'da çift kopyayı listede kaldır


Ben bir dict listesi var ve ben aynı anahtar ve değer çiftleri ile dikte çıkarmak istiyorum.

Bu liste için: [{'a': 123}, {'b': 123}, {'a': 123}]

Bunu iade etmek istiyorum: [{'a': 123}, {'b': 123}]

Başka bir örnek:

Bu liste için: [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]

Bunu iade etmek istiyorum: [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]


76
2018-02-24 07:46


Menşei


Çözmeyi denediğiniz asıl sorun hakkında daha fazla bilgi verir misiniz? Bu tuhaf bir sorun gibi görünüyor. - gfortune
Birkaç dict listesi birleştiriyorum ve çiftleri var. Bu kopyaları çıkarmam gerekiyor. - Brenden
İçinde bir çözüm buldum stackoverflow.com/questions/480214/... kullanımı olmadan bir cevapta set() - Sebastian Wagner


Cevaplar:


Bunu dene:

[dict(t) for t in {tuple(d.items()) for d in l}]

Strateji, sözlük listesini listenin sözlüğün içeriklerini içerdiği bir tupl listesine dönüştürmektir. Tuplelar karma hale gelebileceğinden, çiftleri set (kullanarak anlama koymak burada, yaşlı python alternatifi olurdu set(tuple(d.items()) for d in l)) ve bundan sonra, tuples ile sözlükleri yeniden oluşturun. dict.

nerede:

  • l orijinal liste
  • d listedeki sözlüklerden biridir
  • t bir sözlükten oluşturulan tupllerden biridir

Düzenleme: Siparişi korumak isterseniz, yukarıdaki tek liner o zamandan beri çalışmayacaktır. set bunu yapmaz. Ancak, birkaç satır kodla, bunu da yapabilirsiniz:

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

Örnek çıktı:

[{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]

Not: @alexis tarafından işaret edildiği gibi, aynı anahtar ve değerlere sahip iki sözlük aynı tuple neden olmaz. Farklı bir ekleme / çıkarma anahtarları geçmişini geçerse bu olabilirdi. Sorununuz buysa, sıralamayı düşünün. d.items() önerdiği gibi.


135
2018-02-24 07:51



bu örnekte l nedir? (d için l içinde) - Brenden
@Brenden Cevabı bu bilgilerle güncelledim. l üzerinde çalıştığın liste. - jcollado
Güzel çözüm, ama bir hata var: d.items() öğelerin belirli bir sırayla döndürülmesi garanti edilmez. Yapmalısın tuple(sorted(d.items())) Aynı anahtar / değer çiftleri için farklı tupller almamanızı sağlamak için. - alexis
@alexis Birkaç test yaptım ve gerçekten haklısın. Çok sayıda anahtar arasına eklenir ve daha sonra kaldırılırsa, durum bu olabilir. Yorumunuz için çok teşekkürler. - jcollado
Not, bu bir dicts listesinden yüklerseniz, bu işe yaramaz. json modül benim yaptığım gibi - Dhruv Ghulati


Liste anlamalarına dayanan bir başka tek liner:

>>> 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}]

Burada kullanabileceğimiz için dict karşılaştırma, sadece ilk listenin geri kalanında olmayan öğeleri tutuyoruz (bu nosyona sadece indeks üzerinden erişilebilir) n, dolayısıyla kullanımı enumerate).


28
2018-02-24 09:05



Bu, ilk cevapla karşılaştırıldığında listelerden oluşan sözlüklerin bir listesi için de çalışır. - gbozee
Bu, aynı zamanda, sözlüklerinizde bir cevap olarak, en iyi cevabın aksine bir değer olarak çalışabiliyorsa da çalışır. - Steve Rossiter
Bu benim için seçilen cevaptan daha iyi çalıştı. - nikhilvj


Bazen eski tarz döngüler hala kullanışlıdır. Bu kod jcollado'dan biraz daha uzun, fakat okunması çok kolay:

a = [{'a': 123}, {'b': 123}, {'a': 123}]
b = []
for i in range(0, len(a)):
    if a[i] not in a[i+1:]:
        b.append(a[i])

12
2018-02-24 08:10



0içinde range(0, len(a)) gerekli değil. - Juan Antonio


Serileştirilmiş JSON nesneleri gibi iç içe geçmiş sözlüklerde çalışıyorsanız, diğer yanıtlar çalışmaz. Bu durumda şunları kullanabilirsiniz:

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]

8
2017-08-02 13:52





Siparişi korumak istiyorsanız, o zaman yapabilirsiniz

from collections import OrderedDict
print OrderedDict((frozenset(item.items()),item) for item in data).values()
# [{'a': 123, 'b': 1234}, {'a': 3222, 'b': 1234}]

Sipariş önemli değilse, o zaman yapabilirsiniz

print {frozenset(item.items()):item for item in data}.values()
# [{'a': 3222, 'b': 1234}, {'a': 123, 'b': 1234}]

7
2018-04-29 07:52





Bir seti kullanabilirsiniz, ancak dikteleri yıkanabilir bir türe dönüştürmeniz gerekir.

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)

Eşsiz şimdi eşittir

set([(('a', 3222), ('b', 1234)), (('a', 123), ('b', 1234))])

Dicts geri almak için:

[dict(x) for x in unique]

0
2018-02-24 08:03





Evrensel bir cevap değilama listeniz olsaydı sıralanmış bazı tuşlarla, böyle:

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}]

o zaman çözüm şu kadar basit:

import itertools
result = [a[0] for a in itertools.groupby(l)]

Sonuç:

[{'a': {'b': 31}, 't': 1},
{'a': {'b': 145}, 't': 2},
{'a': {'b': 25231}, 't': 2},
{'a': {'b': 112}, 't': 3}]

İç içe geçmiş sözlüklerle çalışır ve (belli ki) düzeni korur.


0
2018-06-14 07:49