Sözlükleri Python'da nasıl birleştiririm?


91
d3 = dict(d1, **d2)

Bunun sözlüğü birleştirdiğini anlıyorum. Ama benzersiz mi? Ya d1, d2 ile aynı anahtara ancak farklı değere sahipse? D1 ve d2'nin birleştirilmesini istiyorum, ancak yinelenen anahtar varsa d1'in önceliği var.


9
**Tüm anahtarlar d2dizge değilse , bu numaranın anahtar kelime bağımsız değişkeninin kötüye kullanılması olarak kabul edildiğini lütfen unutmayın . Anahtarların d2tümü dizge değilse , bu Python 3.2'de ve Jython, IronPython ve PyPy gibi alternatif Python uygulamalarında başarısız olur. Örneğin, mail.python.org/pipermail/python-dev/2010-April/099459.html adresine bakın .
Mark Dickinson

Yanıtlar:


154

.update()Orijinaline artık ihtiyacınız yoksa yöntemi kullanabilirsiniz d2:

Mevcut anahtarların üzerine yazarak sözlüğü diğerlerinden anahtar / değer çiftleriyle güncelleyin . Dönüş None.

Örneğin:

>>> d1 = {'a': 1, 'b': 2} 
>>> d2 = {'b': 1, 'c': 3}
>>> d2.update(d1)
>>> d2
{'a': 1, 'c': 3, 'b': 2}

Güncelleme:

Elbette yeni bir birleştirilmiş sözlük oluşturmak için önce sözlüğü kopyalayabilirsiniz. Bu gerekli olabilir veya olmayabilir. Sözlüğünüzde bileşik nesneler (listeler veya sınıf örnekleri gibi diğer nesneleri içeren nesneler) copy.deepcopyolması durumunda da dikkate alınmalıdır.


1
Bu durumda, çakışan anahtarlar bulunursa, d1 öğeleri doğru şekilde öncelik
kazanmalıdır

Hâlâ ihtiyacınız varsa, sadece bir kopyasını alın. d3 = d2.copy () d3.update (d1) ancak d1 + d2'nin dile eklendiğini görmek istiyorum.
stach

4
d1 + d2 sorunludur çünkü çatışmalar sırasında bir sözlüğün önceliği olması gerekir ve hangisinin olduğu özellikle açık değildir.
rjh

d1 + d2 yalnızca Python bir çoklu harita kazanırsa uygulanacaktır, aksi takdirde kullanıcının belirsizliği 8 bayt yazma kazancı için çok kafa karıştırıcıdır.
Nick Bastin

Bu örnekteki sözlükte nesneler var: isinstance(int, object) is Truehenüz deepcopygerekli görünmüyor.
Antony Hatchkins

43

Python2'de,

d1={'a':1,'b':2}
d2={'a':10,'c':3}

d1, d2'yi geçersiz kılar:

dict(d2,**d1)
# {'a': 1, 'c': 3, 'b': 2}

d2, d1'i geçersiz kılar:

dict(d1,**d2)
# {'a': 10, 'c': 3, 'b': 2}

Bu davranış sadece bir uygulama şansı değildir; belgelerde garanti edilmektedir :

Hem konumsal bağımsız değişkende hem de anahtar sözcük bağımsız değişkeni olarak bir anahtar belirtilirse, anahtar sözcükle ilişkili değer sözlükte tutulur.


3
Örnekleriniz Python 3.2'de ve Jython, PyPy ve IronPython'un mevcut sürümlerinde başarısız olacaktır (bir TypeError oluşturarak): Python'un bu sürümleri için, gösterimle bir dikteyi iletirken, bu diktenin **tüm anahtarları dizeler olmalıdır. Daha fazlası için mail.python.org/pipermail/python-dev/2010-April/099427.html adresinden başlayan python-dev iş parçacığına bakın .
Mark Dickinson

@Mark: Uyarılar için teşekkürler. Kodu, CPython dışı uygulamalarla uyumlu hale getirmek için düzenledim.
unutbu

3
anahtarlarınız dizi ve sayılardan oluşuyorsa başarısız olur. örneğin. d1 = {(1, 'a'): 1, (1, 'b'): 0,} d2 = {(1, 'a'): 1, (2, 'b'): 2, (2, 'a'): 1,}
MySchizoBuddy

Paket açma sözdizimi ile ilgili olarak, python 3.5'te yapılacak değişiklikler için bu gönderiye bakın .
Ioannis Filippidis

Bunun d = dict(**d1, **d2)işe yaradığını söyleyecektim , ama yorumlarında @IoannisFilippidis'in atıfta bulunduğu şey bu. Belki de pasajı buraya dahil etmek daha net olurdu, işte burada.
dwanderson

14

d1Çatışmalarda öncelik sahibi olmak istiyorsanız , şunları yapın:

d3 = d2.copy()
d3.update(d1)

Aksi takdirde, ters d2ve d1.


1

Benim çözümüm bir birleştirme işlevi tanımlamak . Sofistike değil ve sadece bir satıra mal oluyor. İşte Python 3'teki kod.

from functools import reduce
from operator import or_

def merge(*dicts):
    return { k: reduce(lambda d, x: x.get(k, d), dicts, None) for k in reduce(or_, map(lambda x: x.keys(), dicts), set()) }

Testler

>>> d = {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
>>> d_letters = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d, d_letters)
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d_letters, d)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge(d)
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
>>> merge(d_letters)
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> merge()
{}

Rasgele sayıdaki sözlük argümanları için çalışır. Bu sözlükte yinelenen anahtarlar varsa, bağımsız değişken listesindeki en sağdaki sözlükteki anahtar kazanır.


1
İçinde bir .updateçağrı bulunan ( merged={}ardından gelen for d in dict: merged.update(d)) basit bir döngü daha kısa, daha okunaklı ve daha verimli olacaktır.
Mark Dickinson

1
Yoksa gerçekten kullanmak istiyorsanız reduceve lambdas, nasıl return reduce(lambda x, y: x.update(y) or x, dicts, {})?
Mark Dickinson

1
Kodunuzu kabukta deneyebilir ve doğru olup olmadığını görebilirsiniz. Yapmaya çalıştığım şey, aynı işlevselliğe sahip çeşitli sözlük argümanları alabilen bir işlev yazmaktı. Lambda altında x.update (y) kullanmamak daha iyidir, çünkü her zaman None döndürür . Ve çeşitli sayıda sözlük argümanı alan ve sağlanan işlevle yinelenen anahtarlarla ilgilenen daha genel bir merge_with işlevi yazmaya çalışıyorum . İşim bittiğinde, çözümün daha alakalı olduğu başka bir konu başlığına göndereceğim.
Lei Zhao

İşte daha genel çözümü yazdığım bağlantı . Hoş geldiniz ve bir göz atın.
Lei Zhao


1

Başlarken Python 3.9, operatör |iki sözlükten birleştirilmiş anahtarlar ve değerlerle yeni bir sözlük oluşturur:

# d1 = { 'a': 1, 'b': 2 }
# d2 = { 'b': 1, 'c': 3 }
d3 = d2 | d1
# d3: {'b': 2, 'c': 3, 'a': 1}

Bu:

D2 ve d1'in birleştirilmiş anahtarları ve değerleriyle yeni bir sözlük d3 oluşturur. D2 ve d1 anahtarları paylaştığında d1 değerleri öncelikli olur.


Ayrıca |=, d1 değerlerine öncelik vererek d1'i birleştirerek d2'yi değiştiren operatöre dikkat edin :

# d1 = { 'a': 1, 'b': 2 }
# d2 = { 'b': 1, 'c': 3 }
d2 |= d1
# d2: {'b': 2, 'c': 3, 'a': 1}


0

Yukarıda da belirtildiği gibi kullanmanın d2.update(d1)en iyi yaklaşım olduğuna ve d2yine de ihtiyacınız varsa önce kopyalayabileceğinize inanıyorum .

Bununla birlikte, bunun dict(d1, **d2)genel olarak sözlükleri birleştirmenin aslında kötü bir yolu olduğunu belirtmek isterim , çünkü anahtar kelime argümanlarının dizge olması gerekir, bu nedenle eğer dictböyle bir şeye sahipseniz başarısız olur :

{
  1: 'foo',
  2: 'bar'
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.