簡體   English   中英

Pythonic方法將鍵與單個字典的公共值合並

[英]Pythonic way to merge keys with common values for a single dictionary

如何將字典的鍵與常用值合並到元組中。 例如:

A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}

output = {('E2', 'E5'): {'5', '7'}, ('E3', 'E8'): {'4', '8'}}

我的嘗試:

A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}

output = {}
seen = []
for k, v in A.items():
    if v not in [s[1] for s in seen]: # not seen this value yet
        print('NOT SEEN')
        print(k, v)
        seen.append([k,v])
        output[k] = v
    else: # already seen it 
        print('SEEN')
        print(k, v)
        # determine where we've seen it 
        where = [x for x in seen if x[1]==v]
        output.pop(where[0][0])
        output[(where[0][0], k)] = v


print('OUTPUT = ', output)       

這打印:

OUTPUT =  {('E2', 'E5'): {'7', '5'}, ('E3', 'E8'): {'4', '8'}}

我會在兩個過程中進行轉換:

>>> A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}

# First pass:  Create a reverse one-to-many mapping. 
# The original set() value gets converted to a hashable frozenset()
# and used as a key.  The original scalar string key gets accumulated
# in a list to track the multiple occurrences.
>>> reverse = {}
>>> for key, value in A.items():
        reverse.setdefault(frozenset(value), []).append(key)

# Second pass:  reverse the keys and values.  The list of matching
# values gets converted to a hashable tuple (as specified by the OP)
# and the frozenset() gets restored back to the original set() type.
>>> {tuple(value) : set(key) for key, value in reverse.items()}
{('E2', 'E5'): {'5', '7'}, ('E3', 'E8'): {'8', '4'}}

這給出了OP期望的輸出。

注意,輸入字典沒有保證順序,也沒有原始輸入中的任何集合。 因此,輸出不能保證條款的有序排序。

import itertools

A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}

def key(x): 
    # List supports ordering
    return sorted(list(x[1]))

def gen():
    for (group_key, group) in itertools.groupby(sorted(A.items(), key=key), key=key):
        gl = list(group)
        yield (tuple(x[0] for x in gl), 
               gl[0][1]  # group_key is a list, but we want original set
              )

print(dict(gen()))

如果您已准備好說服set-> list-> set轉換是安全的,那么您可以制作單行而不是生成器:

print(dict((tuple(g[0] for g in group), set(group_key)) for 
           (group_key, group) in 
           itertools.groupby(sorted(A.items(), key=key), key=key)))

UPD:那么,到底發生了什么?

首先,我們通過調用.items()將dict轉換為可迭代的元組。 我們想要將具有相同第二個元素(具有索引1或前一個dict值)的迭代項組合在一起。 這正是itertools.groupby所做的。 參數是一個可迭代的鍵,我們將通過它組合。 看起來, key=lambda kv: kv[1]是要走的路。 不幸的是。 我們可以比較集合的相等性,但是文檔說可迭代應該是有序的。 並且sorted功能需要密鑰與訂單相當。 無法按列表的順序比較集。 我們可以安全地創建一個包含與set相同元素的列表,但是我們應該對它進行排序(相等的集合可以生成具有不同順序的列表, {5, 7} == {7, 5} ,但是[5, 7] != [7, 5] )。

現在,在排序和分組之后,我們有以下數據結構:

[
   (key_dict_value as list, iterable of (dict_key, dict_value) that has dict_value == key_dict_value),
   ...
]

現在我們可以迭代這個iterable並創建另一個可迭代的元組。 我們采用每個元組的第二個元素(可迭代,索引為1)並將其轉換為元組(這是我們未來字典的關鍵)。 我們未來字典的值是原始字典中的值。 我們可以從元組的第二個元素的某個元素(這個可迭代不能為空,因為groupby不能生成空組,查看第一個片段)或者從key_dict_value轉換回列表(它是安全的,因為這個列表是從集合中生成,所以它沒有相同的元素,請參閱第二個片段)。

UPD2

當我寫作解釋時,我發現平等的關鍵不適合sorted但是對於groupby很好,所以這里甚至更簡單的解決方案,沒有定義key功能並將列表轉換回設置:

print(dict((tuple(g[0] for g in group), group_key) for 
           (group_key, group) in itertools.groupby(sorted(A.items(), 
                                                          key=lambda x: sorted(list(x[1]))), 
                                                   key=lambda x: x[1])))

你可以試試這個:

from collections import defaultdict

A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}

second_new = defaultdict(list)

for a, b in A.items():
    second_new[tuple(b)].append(a)

final_dict = {tuple(b):set(a) for a, b in second_new.items()}

輸出:

{('E8', 'E3'): {'8', '4'}, ('E5', 'E2'): {'5', '7'}}

這是我使用理解的方法。 只需要兩個中間步驟,並且只使用內置數據類型。

# get unique values from original dict
targ_values = set([tuple(v) for v in A.values()])

# build lists of original keys that match the temp_keys
targ_values = {targ_value:[orig_key for orig_key, orig_value in A.items() if tuple(orig_value) == targ_value] for targ_value in targ_values}

# reverse the order of keys & values and convert types to get desired output
output = {tuple(v):set(k) for k, v in targ_values.items()}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM