2010-05-09 58 views
82
d3 = dict(d1, **d2) 

Tôi hiểu rằng điều này sẽ hợp nhất từ ​​điển. Nhưng, nó có độc đáo không? Điều gì xảy ra nếu d1 có cùng khóa với d2 nhưng giá trị khác nhau? Tôi muốn d1 và d2 được sáp nhập, nhưng d1 có ưu tiên nếu có khóa trùng lặp.Làm cách nào để kết hợp các từ điển cùng nhau trong Python?

+9

Hãy lưu ý rằng mẹo này được coi là lạm dụng đối số từ khóa '**' trừ khi tất cả các khóa của 'd2' là các chuỗi. Nếu không phải tất cả các khóa của 'd2' là các chuỗi, điều này không thành công trong Python 3.2, và trong các triển khai thay thế của Python như Jython, IronPython và PyPy. Xem, ví dụ: http://mail.python.org/pipermail/python-dev/2010-April/099459.html. –

+1

có thể trùng lặp của [Làm cách nào tôi có thể hợp nhất hai từ điển Python trong một biểu thức?] (Http://stackoverflow.com/questions/38987/how-can-i-merge-two-python-dictionaries-in-a-single -expression) –

Trả lời

136

Bạn có thể sử dụng phương pháp .update() nếu bạn không cần bản gốc d2 nữa:

Cập nhật từ điển với các cặp khóa/giá trị từ khác, ghi đè lên các phím hiện. Trả lại None.

ví dụ .:

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

Cập nhật:

Tất nhiên bạn có thể sao chép từ điển đầu tiên để tạo ra một cái mới đã merge. Điều này có thể hoặc có thể không cần thiết. Trong trường hợp bạn có các đối tượng ghép (các đối tượng chứa các đối tượng khác, như các danh sách hoặc các cá thể lớp) trong từ điển của bạn, cũng cần xem xét copy.deepcopy.

+1

Với trường hợp này các yếu tố d1 nên được ưu tiên chính xác nếu các phím xung đột được tìm thấy –

+0

Trong trường hợp bạn vẫn cần nó, chỉ cần tạo một bản sao. d3 = d2.copy() d3.update (d1) nhưng tôi muốn xem d1 + d2 đang được thêm vào ngôn ngữ. – stach

+4

d1 + d2 có vấn đề vì một từ điển phải có mức độ ưu tiên trong các xung đột, và nó không đặc biệt rõ ràng. – rjh

36

Trong python2,

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

d1 d2 ghi đè: ghi đè

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

d2 d1:

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

Hành vi này không chỉ là một sự may mắn thực hiện; nó được đảm bảo in the documentation:

Nếu một phím được quy định cả trong đối số vị trí và như một đối số từ khóa , giá trị gắn liền với từ khóa được giữ lại trong từ điển .

+3

Ví dụ của bạn sẽ thất bại (tạo ra một TypeError) trong Python 3.2, và trong các phiên bản hiện tại của Jython, PyPy và IronPython: đối với các phiên bản của Python, khi chuyển một dict với ký hiệu '**', tất cả các khóa của dict đó là chuỗi. Xem chuỗi python-dev bắt đầu tại http://mail.python.org/pipermail/python-dev/2010-April/099427.html để biết thêm. –

+0

@Mark: Cảm ơn những người đứng đầu. Tôi đã chỉnh sửa mã để làm cho nó tương thích với việc triển khai không CPython. – unutbu

+3

nó không thành công nếu các phím của bạn là bộ dữ liệu chuỗi và số. cho ví dụ. d1 = {(1, 'a'): 1, (1, 'b'): 0,} d2 = {(1, 'a'): 1, (2, 'b'): 2, (2 , 'a'): 1,} – MySchizoBuddy

11

Nếu bạn muốn d1 để được ưu tiên trong các cuộc xung đột, làm:

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

Nếu không, ngược d2d1.

1

Giải pháp của tôi là xác định hàm hợp nhất. Nó không phức tạp và chỉ tốn một dòng. Dưới đây là mã trong Python 3.

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()) } 

thử nghiệm

>>> 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() 
{} 

Nó hoạt động cho số tùy ý của các đối số từ điển. Đã có bất kỳ khóa trùng lặp nào trong từ điển đó hay không, khóa từ từ điển ngoài cùng bên phải trong danh sách đối số sẽ thắng.

+1

Một vòng lặp đơn giản với một cuộc gọi '.update' trong nó (' merged = {} 'theo sau bởi' for d in dict: merged.update (d) ') sẽ ngắn hơn, dễ đọc hơn và hiệu quả hơn. –

+1

Hoặc nếu bạn thực sự muốn sử dụng 'reduce' và' lambda's, làm thế nào về 'return reduce (lambda x, y: x.update (y) hoặc x, dicts, {})'? –

+0

Bạn có thể thử mã của mình trong trình bao và xem mã đó có đúng không. Những gì tôi đã cố gắng làm là viết một hàm có thể lấy số lượng các đối số từ điển khác nhau với cùng chức năng.Tốt hơn là không sử dụng x.update (y) trong lambda, vì nó luôn trả về _None_. Và tôi đang cố gắng viết một hàm tổng quát hơn _merge \ _with_ lấy số lượng đối số từ điển khác nhau và xử lý các khóa trùng lặp với hàm được cung cấp. Khi tôi hoàn thành, tôi sẽ đăng nó trong một chủ đề khác, nơi giải pháp có liên quan hơn. –

0

Tôi tin rằng, như đã nêu ở trên, sử dụng d2.update(d1) là cách tiếp cận tốt nhất và bạn cũng có thể sao chép d2 trước nếu bạn vẫn cần.

Mặc dù, tôi muốn chỉ ra rằng dict(d1, **d2) thực sự là một cách xấu để merge dictionnaries nói chung kể từ khi đối số từ khóa cần phải được chuỗi, do đó nó sẽ thất bại nếu bạn có một dict như:

{ 
    1: 'foo', 
    2: 'bar' 
} 
Các vấn đề liên quan