Làm thế nào để hợp nhất nhiều quân số với cùng một khóa?


83

Tôi có nhiều cặp số / cặp khóa-giá trị như thế này:

d1 = {key1: x1, key2: y1}  
d2 = {key1: x2, key2: y2}  

Tôi muốn kết quả là một chính tả mới (theo cách hiệu quả nhất, nếu có thể):

d = {key1: (x1, x2), key2: (y1, y2)}  

Trên thực tế, tôi muốn kết quả d là:

d = {key1: (x1.x1attrib, x2.x2attrib), key2: (y1.y1attrib, y2.y2attrib)}  

Nếu ai đó chỉ cho tôi cách lấy kết quả đầu tiên, tôi có thể tìm ra phần còn lại.


3
@Salil: Chúng ta có thể giả định rằng mỗi khóa có trong tất cả các từ điển không?
Björn Pollex

Có thể có bản sao của các từ điển Python hợp nhất
Johnsyweb

Xin chào Space_C0wb0y, vâng, các khóa có trong tất cả các từ điển.
Salil

Điều tối quan trọng là xác định xem tất cả các hệ phái có khóa giống nhau hay không.
yugr

Câu trả lời:


43

giả sử tất cả các khóa luôn hiện diện trong tất cả các quân số:

ds = [d1, d2]
d = {}
for k in d1.iterkeys():
    d[k] = tuple(d[k] for d in ds)

Lưu ý: Trong Python 3.x, hãy sử dụng mã dưới đây:

ds = [d1, d2]
d = {}
for k in d1.keys():
  d[k] = tuple(d[k] for d in ds)

và nếu dic chứa các mảng numpy:

ds = [d1, d2]
d = {}
for k in d1.keys():
  d[k] = np.concatenate(list(d[k] for d in ds))

3
Tôi nghĩ chỉ cần "cho k trong d1".
Salil

và d.get (k, None) thay cho d [k]
tahir

1
@tahir Điều này có nghĩa là các hệ phái có các khóa không khớp nên việc lặp lại d1là không đúng (có thể bỏ sót các khóa trong các môn phái khác).
yugr

1
Đối với python 3 người sử dụng: d1.iterkeys () = d1.items ()
Riley

Nó vẫn không hoạt động đối với tôi trong Python3.x. Tôi đã thử điều này ngay cả khi các giá trị của tôi không phải là mảng và nó hoạt động. Tuy nhiên, giá trị đầu ra sẽ là mảng. stackoverflow.com/questions/54040858/…
Ric S

73

Đây là một giải pháp chung sẽ xử lý một lượng từ điển tùy ý, với các trường hợp khi các khóa chỉ nằm trong một số từ điển:

from collections import defaultdict

d1 = {1: 2, 3: 4}
d2 = {1: 6, 3: 7}

dd = defaultdict(list)

for d in (d1, d2): # you can list as many input dicts as you want here
    for key, value in d.items():
        dd[key].append(value)

print(dd)

Trình diễn:

defaultdict(<type 'list'>, {1: [2, 6], 3: [4, 7]})

Ngoài ra, để có được của bạn .attrib, chỉ cần thay đổi append(value)thànhappend(value.attrib)


Tôi nghĩ OP muốn các giá trị như tuplekhông list.
user225312

1
@AA: nó có thực sự quan trọng không? tuples sẽ được khôn lanh hơn để xây dựng trong trường hợp tổng quát hơn nhiều dicts đầu vào nơi mà một số phím nay không ở khắp mọi nơi, IMHO
Eli Bendersky

1
Sau đó bạn có thể muốn thực hiện một bình thường dictra khỏi defaultdictvì vậy bạn phải bình thường dicthành vi cho các phím không tồn tại vv: dd = dict(dd)
Ned Deily

@Ned: điểm tốt, nhưng nó phụ thuộc vào việc sử dụng dữ liệu cuối cùng
Eli Bendersky

@Eli: Không có nó không quan trọng nhưng tôi đã chỉ cố gắng để căn nó vào những gì OP muốn và đã hy vọng rằng sẽ có một giải pháp cho các bộ từ bạn :-)
user225312

4

Nếu bạn chỉ có d1 và d2,

from collections import defaultdict

d = defaultdict(list)
for a, b in d1.items() + d2.items():
    d[a].append(b)

4
dict1 = {'m': 2, 'n': 4}
dict2 = {'n': 3, 'm': 1}

Đảm bảo rằng các khóa theo cùng một thứ tự:

dict2_sorted = {i:dict2[i] for i in dict1.keys()}

keys = dict1.keys()
values = zip(dict1.values(), dict2_sorted.values())
dictionary = dict(zip(keys, values))

cho:

{'m': (2, 1), 'n': (4, 3)}

1
Thứ tự của các phần tử trong values()không được xác định nên bạn có thể đang hợp nhất các giá trị từ các khóa không liên quan.
yugr

Tôi chỉ áp dụng những thay đổi vì thế bây giờ có thể nắm bắt được thông tin phản hồi của bạn
Mahdi Ghelichi

Tôi không nghĩ rằng thay đổi sẽ khắc phục được vấn đề. Bạn cần sử dụng sorted(d.items())hoặc sorted(d.keys())để đạt được kết quả có thể dự đoán được.
yugr

Bạn có thể đưa ra một ví dụ chứng minh điều đó khác không? dict2_sorted là một từ điển được sắp xếp trong python!
Mahdi Ghelichi

Thực tế là nó hoạt động với các từ điển nhỏ trên máy của bạn không phải là một bằng chứng. Kiểm tra repro tại đây .
yugr

3

Đây là một cách tiếp cận bạn có thể sử dụng sẽ hoạt động ngay cả khi cả hai nhà độc tài không có cùng khóa:

d1 = {'a':'test','b':'btest','d':'dreg'}
d2 = {'a':'cool','b':'main','c':'clear'}

d = {}

for key in set(d1.keys() + d2.keys()):
    try:
        d.setdefault(key,[]).append(d1[key])        
    except KeyError:
        pass

    try:
        d.setdefault(key,[]).append(d2[key])          
    except KeyError:
        pass

print d

Điều này sẽ tạo ra đầu vào bên dưới:

{'a': ['test', 'cool'], 'c': ['clear'], 'b': ['btest', 'main'], 'd': ['dreg']}

set(d1.keys() + d2.keys()) thể thay đổi thành set(list(d1.keys()) + list(d2.keys()))trong câu trả lời (đối với Python 3.x) không? Nếu không nó sẽ ném một TypeError: unsupported operand type(s) for +: 'dict_keys' and 'dict_keys'lỗi, trong python3.x
R4444

1

Cập nhật Python 3.x

Từ câu trả lời của Eli Bendersky:

Python 3 đã loại bỏ dict.iteritems sử dụng dict.items thay thế. Xem Python wiki: https://wiki.python.org/moin/Python3.0

from collections import defaultdict

dd = defaultdict(list)

for d in (d1, d2):
    for key, value in d.items():
        dd[key].append(value)

1

Phương pháp này kết hợp hai phái ngay cả khi các khóa trong hai từ điển khác nhau:

def combine_dict(d1, d2):
    combined = {}
    for k in set(d1.keys()) | set(d2.keys()):
        combined[k] = tuple(d[k] for d in [d1, d2] if k in d)
    return combined

Thí dụ:

d1 = {
    'a': 1,
    'b': 2,
}
d2` = {
    'b': 'boat',
    'c': 'car',
}
combine_dict(d1, d2)
# Returns: {
#    'a': (1,),
#    'b': (2, 'boat'),
#    'c': ('car',)
# }

1

Giả sử rằng bạn có danh sách TẤT CẢ các khóa (bạn có thể lấy danh sách này bằng cách duyệt qua tất cả các từ điển và lấy các khóa của chúng). Hãy đặt tên cho nó listKeys. Cũng thế:

  • listValues là danh sách TẤT CẢ các giá trị cho một khóa duy nhất mà bạn muốn hợp nhất.
  • allDicts: tất cả các từ điển mà bạn muốn hợp nhất.
result = {}
for k in listKeys:
    listValues = [] #we will convert it to tuple later, if you want.
    for d in allDicts:
       try:
            fileList.append(d[k]) #try to append more values to a single key
        except:
            pass
    if listValues: #if it is not empty
        result[k] = typle(listValues) #convert to tuple, add to new dictionary with key k

0
def merge(d1, d2, merge):
    result = dict(d1)
    for k,v in d2.iteritems():
        if k in result:
            result[k] = merge(result[k], v)
        else:
            result[k] = v
    return result

d1 = {'a': 1, 'b': 2}
d2 = {'a': 1, 'b': 3, 'c': 2}
print merge(d1, d2, lambda x, y:(x,y))

{'a': (1, 1), 'c': 2, 'b': (2, 3)}

0

Để bổ sung các giải pháp hai danh sách, đây là một giải pháp để xử lý một danh sách duy nhất .

Danh sách mẫu (liên quan đến NetworkX; được định dạng thủ công tại đây để dễ đọc):

ec_num_list = [((src, tgt), ec_num['ec_num']) for src, tgt, ec_num in G.edges(data=True)]

print('\nec_num_list:\n{}'.format(ec_num_list))
ec_num_list:
[((82, 433), '1.1.1.1'),
  ((82, 433), '1.1.1.2'),
  ((22, 182), '1.1.1.27'),
  ((22, 3785), '1.2.4.1'),
  ((22, 36), '6.4.1.1'),
  ((145, 36), '1.1.1.37'),
  ((36, 154), '2.3.3.1'),
  ((36, 154), '2.3.3.8'),
  ((36, 72), '4.1.1.32'),
  ...] 

Lưu ý các giá trị trùng lặp cho các cạnh giống nhau (được xác định bởi các bộ giá trị). Để đối chiếu những "giá trị" đó với "khóa" tương ứng của chúng:

from collections import defaultdict
ec_num_collection = defaultdict(list)
for k, v in ec_num_list:
    ec_num_collection[k].append(v)

print('\nec_num_collection:\n{}'.format(ec_num_collection.items()))
ec_num_collection:
[((82, 433), ['1.1.1.1', '1.1.1.2']),   ## << grouped "values"
((22, 182), ['1.1.1.27']),
((22, 3785), ['1.2.4.1']),
((22, 36), ['6.4.1.1']),
((145, 36), ['1.1.1.37']),
((36, 154), ['2.3.3.1', '2.3.3.8']),    ## << grouped "values"
((36, 72), ['4.1.1.32']),
...] 

Nếu cần, hãy chuyển đổi danh sách đó thành dict:

ec_num_collection_dict = {k:v for k, v in zip(ec_num_collection, ec_num_collection)}

print('\nec_num_collection_dict:\n{}'.format(dict(ec_num_collection)))
  ec_num_collection_dict:
  {(82, 433): ['1.1.1.1', '1.1.1.2'],
  (22, 182): ['1.1.1.27'],
  (22, 3785): ['1.2.4.1'],
  (22, 36): ['6.4.1.1'],
  (145, 36): ['1.1.1.37'],
  (36, 154): ['2.3.3.1', '2.3.3.8'],
  (36, 72): ['4.1.1.32'],
  ...}

Người giới thiệu


0

Từ câu trả lời blubb:

Bạn cũng có thể trực tiếp tạo bộ tuple bằng cách sử dụng các giá trị từ mỗi danh sách

ds = [d1, d2]
d = {}
for k in d1.keys():
  d[k] = (d1[k], d2[k])

Điều này có thể hữu ích nếu bạn có một đơn đặt hàng cụ thể cho bộ giá trị của mình

ds = [d1, d2, d3, d4]
d = {}
for k in d1.keys():
  d[k] = (d3[k], d1[k], d4[k], d2[k]) #if you wanted tuple in order of d3, d1, d4, d2

0

Thư viện này đã giúp tôi, tôi có một danh sách chính tả các khóa lồng nhau có cùng tên nhưng có giá trị khác nhau, mọi giải pháp khác vẫn ghi đè các khóa lồng nhau đó.

https://pypi.org/project/deepmerge/

from deepmerge import always_merger

def process_parms(args):
    temp_list = []
    for x in args:
        with open(x, 'r') as stream:
            temp_list.append(yaml.safe_load(stream))

    return always_merger.merge(*temp_list)

0

Nếu các khóa được lồng vào nhau:

d1 = { 'key1': { 'nkey1': 'x1' }, 'key2': { 'nkey2': 'y1' } } 
d2 = { 'key1': { 'nkey1': 'x2' }, 'key2': { 'nkey2': 'y2' } }
ds = [d1, d2]
d = {}
for k in d1.keys():
    for k2 in d1[k].keys():
        d.setdefault(k, {})
        d[k].setdefault(k2, [])
        d[k][k2] = tuple(d[k][k2] for d in ds)

sản lượng:

{'key1': {'nkey1': ('x1', 'x2')}, 'key2': {'nkey2': ('y1', 'y2')}}

-4

Một khả năng nhỏ gọn

d1={'a':1,'b':2}
d2={'c':3,'d':4}
context={**d1, **d2}
context
{'b': 2, 'c': 3, 'd': 4, 'a': 1}

câu hỏi là về việc hợp nhất các phái với cùng một khóa. của bạn không phải là câu trả lời bắt buộc.
Pbd
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.