【问题标题】:Mapping of Keys using dictionary and lists in Python在 Python 中使用字典和列表映射键
【发布时间】:2021-12-30 14:44:58
【问题描述】:

我有一个字典列表列表,如下所示:

ini_dict = [[
       {'nikhil': 1, 'vashu': 5, 'manjeet': 10, 'akshat': 16}, 
       {'nikhil': 1, 'vashu': 5, 'manjeet': 10, 'akshat': 15}
]]

第 1 步:降低一级

我已经修改并减少了一个级别,如下所示:

mod = []
for i in ini_dict:
    for j in i:
        mod.append({item: values for item, values in j.items()}) 

这给了我如下输出:

[
   {'nikhil': 1, 'vashu': 5, 'manjeet': 10, 'akshat': 15}, 
   {'nikhil': 1, 'vashu': 5, 'manjeet': 10, 'akshat': 15}
]

第 2 步:将键替换为另一个字典中的值

现在,我有另一套 keys 字典 result_dict1 我使用键(此处为小写)将上述数据mod 中的键替换为相关值(此处为大写)。

result_dict1 = {
   "nikhil": "Nikhil",
   "vashu": "Vashu",
   "manjeet": "Manjeet",
   "akshat": "Akshat"
}  

我试过的代码

现在,我尝试了以下代码,但它没有给我所需的输出:

final = []
for j, k in result_dict1.items():
    for i in mod:
        for x, y in i.items():
            final += [{k: y}]  

输出

[{'Nikhil': 1}, {'Nikhil': 5}, {'Nikhil': 10}, {'Nikhil': 15}, {'Nikhil': 1}, {'Nikhil': 5}, {'Nikhil': 10}, {'Nikhil': 15}, {'Vashu': 1}, {'Vashu': 5}, {'Vashu': 10}, {'Vashu': 15}, {'Vashu': 1}, {'Vashu': 5}, {'Vashu': 10}, {'Vashu': 15}, {'Manjeet': 1}, {'Manjeet': 5}, {'Manjeet': 10}, {'Manjeet': 15}, {'Manjeet': 1}, {'Manjeet': 5}, {'Manjeet': 10}, {'Manjeet': 15}, {'Akshat': 1}, {'Akshat': 5}, {'Akshat': 10}, {'Akshat': 15}, {'Akshat': 1}, {'Akshat': 5}, {'Akshat': 10}, {'Akshat': 15}]  

问题

键被替换,但组合为1:N

预期输出

[
   {'Nikhil': 1, 'Vashu': 5, 'Manjeet': 10, 'Akshat': 15}, 
   {'Nikhil': 1, 'Vashu': 5, 'Manjeet': 10, 'Akshat': 15}
]

【问题讨论】:

    标签: python dictionary transformation


    【解决方案1】:

    您似乎没有检查 mod 中的内部字典的键是否与替换字典中的键匹配,这是一个问题。

    带有字典推导的列表推导会产生结果:

    >>> [{result_dict1[key]: value for key, value in inner_dict.items()}
         for inner_dict in mod]
    
    [{'Nikhil': 1, 'Vashu': 5, 'Manjeet': 10, 'Akshat': 15},
     {'Nikhil': 1, 'Vashu': 5, 'Manjeet': 10, 'Akshat': 15}]
    

    因此,dict 理解正在更改 mod 的内部字典,以便从 result_dict1 替换键。列表推导有助于为每个内部字典做到这一点。

    如果result_dict1 不够全面,就会出错。


    上面的推导可以解包为

    # this is the final result; we'll fill in this
    end_list = []
    
    # foreach dictionary in `mod`...
    for inner_dict in mod:
        # define anew empty dict
        new_inner_dict = {}
        
        # foreach (key, val) pair of the `inner_dict`...
        for key, value in inner_dict.items():
            # get the `new_key` from the replacer mapping
            new_key = result_dict1[key]
            
            # put it into the new dict (but the value is the same)
            new_inner_dict[new_key] = value
    
        # above for ended, we have a new_inner_dict; save it
        end_list.append(new_inner_dict)
    
    print(end_list)
    

    【讨论】:

    • 酷。明白了兄弟。我没有得到代码中的 for 循环部分。你能帮我解决这个问题吗?
    • @whatsinthename 您的意思是在您的代码中还是在此代码中?
    • 请不要假设性别,谢谢。
    • 我的意思是在你的代码中
    • @whatsinthename 我写了一个等效的 for 循环版本的理解,希望它有所帮助。两个代码是~等价的。
    【解决方案2】:

    问题

    你快到了:

    • 第 1 步:按预期工作
    • 第 2 步:迭代键映射 result_dict1 而不是 mod

    已修复

    我在哪里添加了 cmets

    • 删除了循环或将其添加回来稍作修改
    • 引入了一个内部集合 (dict) 以保持源分离
    ini_dict = [[
           {'nikhil': 1, 'vashu': 5, 'manjeet': 10, 'akshat': 16}, 
           {'nikhil': 1, 'vashu': 5, 'manjeet': 10, 'akshat': 15}
    ]]
    
    # step 2:
    mod = []
    for i in ini_dict:
        for j in i:
            mod.append({item: values for item, values in j.items()}) 
    
    print(f"step 1:\n{mod}")
    
    # step 2:
    result_dict1 = {
       "nikhil": "Nikhil",
       "vashu": "Vashu",
       "manjeet": "Manjeet",
       "akshat": "Akshat"
    }  
    
    final = []
    # for j, k in result_dict1.items():
    for i in mod:
        inner = {}  # collect inner separately
        for x, y in i.items():
            k = result_dict1[x]  # lookup in dict, instead for-loop
            # final += [{k: y}]
            inner[k] = y  # add to inner (not to final outer) !as dict-entry! (not as list)
        final.append(inner)  # keep separation
        
    print(f"step 2:\n{final}")
    

    打印:

    step 1:
    [{'nikhil': 1, 'vashu': 5, 'manjeet': 10, 'akshat': 16}, {'nikhil': 1, 'vashu': 5, 'manjeet': 10, 'akshat': 15}]
    step 2:
    [{'Nikhil': 1, 'Vashu': 5, 'Manjeet': 10, 'Akshat': 16}, {'Nikhil': 1, 'Vashu': 5, 'Manjeet': 10, 'Akshat': 15}]
    

    注意: 您原来的外部 for 循环 k for j, k in result_dict1.items() 可以重写为:

    keys = [k for j, k in result_dict1.items() if j == x] # for-loop as list-comprehension with added conditional
    k = keys[0]  # key expected as first element in resulting list
    

    相当复杂.. 另外,我们希望找到密钥,但如果列表 keys 为空怎么办?然后keys[0] 会引发IndexError: list index out of range

    我们可以从这里的 dict 中受益并简化查找:k = result_dict1[x]

    建议:命名有帮助

    据我所知,变量的命名可以改进。 那么也许这个逻辑缺陷会更早被识别出来。

    例如看到inneri 更有意义。它可以像人类语言一样被阅读和理解 - 无需在内存中保留名称字典或映射,如“i:内部列表或字典”作为额外的认知负荷。

    固定替代

    第 2 步的当前实现与 第 1 步的实现进行比较:

    mod = []
    for i in ini_dict:
        for j in i:
            mod.append({item: values for item, values in j.items()}) 
    
    print(f"step 1:\n{mod}")
    

    我们也可以在这里重用被称为dict理解的模式

    final = []
    for i in mod:
        final.append({result_dict1[x]: values for x, values in i.items()})
        
    print(f"step 2:\n{final}")
    

    好处:

    • 视觉相似度可以识别为形状(即使在大文件中缩小到 10% 时)
    • 看起来更简单,因为熟悉(在我们已经理解了第 1 步之后)
    • 更容易识别哪些部分相似(与第 1 步相同)以及它们的不同之处(例如,没有嵌套级别的 for 循环)

    这也称为代码对称。参见例如卡洛斯·布莱(2014):Code Symmetry

    【讨论】:

    • 哦,忘了在mod中保持(两个)列表的分隔。目前结果是扁平化 ?将在几个小时内修复。
    • 已修复和更新。借此机会说明命名如何有助于减少认知负担和简化理解,甚至可以防止错误。
    • 虽然强调了命名的重要性,但为什么Fixed Alternative中还有ijvalues?为什么在使用 unpythonic "[]-for-append" 习语的 sn-p 中没有发生更具可读性的列表理解?
    • @Neither 很好地观察到了我的注意力! (a) 保留建议作为奖励,但专注于微创修复。 改进的命名需要首先阐明上下文语义(例如,iinner_list 还是 scored_groups 包含人 = 带有分数的名称。(b) 可读性是主观的:list-理解是一个Pythonic idiom。因此它对于高级Pythonistas来说是可以理解的。大多数代码阅读者可以理解polyglot for-loops。所以我适应了观众的技能水平和重复使用[]-for-append(多么棒的术语?️)来构建 OP 的已知模式。?️
    猜你喜欢
    • 2020-03-15
    • 1970-01-01
    • 2017-06-28
    • 2019-07-10
    • 2021-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    相关资源
    最近更新 更多