【问题标题】:Better approach for python dictionary problempython字典问题的更好方法
【发布时间】:2018-12-15 21:12:32
【问题描述】:

这里是样本数据。输入目录中的所有内容都是动态的。唯一的问题是数据字典将为 input_dict 中的每个键值修复 7 个不同的值。它可能只有 1 或 0 个值。

input_dict = { 'all_val' : ['a', 'b', 'c' ],
               '2nd_group' : ['a', 'b'] ,
               '3rd_grp' : ['a' , 'c']}
data = {  
'a' :      [1,0,1,0,0,0,1],
'b' :      [0,0,1,1,0,1,0],
'c' :      [0,1,1,0,0,0,1]    }

required_output = {'2nd_group': 5, '3rd_grp': 4, 'all_val': 6}

逻辑:对于 all_val,取 a 、 b 和 c 并转到数据字典。如果 a[0],b[0],c[0] 中的任何一个为 1,则应考虑 1。 a[1],b[1],c[1] 的方式相同 ...最后计算所有 1 .

我的解决方案:

temp_dict = {}
output_dict = {}

for a in input_dict.keys():
    temp_dict[a] = [0]*7

for key, value in input_dict.items():
    for v in value:
        for j , d in enumerate(data[v]):
            temp_dict[key][j] = max( temp_dict[key][j] , d  )

for k,v in temp_dict.items():
    total = 0
    for t in temp_dict[k]:
        total = total + t
    output_dict[k] = total

print output_dict

有没有办法提高性能或解决这个问题的任何其他方法。

【问题讨论】:

  • 您总是可以减少代码量,并像这样一步完成全部编写:print({k: sum(max(data[key][index] for key in keys) for index in range(7)) for k, keys in input_dict.items()}),但我不确定它是否更具可读性。有些部分可以简化,例如搜索 a、b 和 c 的最大值,或者最后的总和。
  • 如果数据字典只包含 7 位,则表示为 7 个元素的列表是雄心勃勃的 - 为什么不使用整数并使用位掩码?

标签: python


【解决方案1】:

您可以进行一些调整并简化逻辑。例如,您无需在第一遍中单独创建密钥。您可以在第二遍中跳过 temp dict。整体逻辑可以简化。

input_dict = { 'all_val' : ['a', 'b', 'c' ],
               '2nd_group' : ['a', 'b'] ,
               '3rd_grp' : ['a' , 'c']}
data = {  
'a' :      [1,0,1,0,0,0,1],
'b' :      [0,0,1,1,0,1,0],
'c' :      [0,1,1,0,0,0,1]    }

#required_output = {'2nd_group': 5, '3rd_grp': 4, 'all_val': 6}
res = {} 
for key,value in input_dict.items():
    output = 0
    #create a zip from the lists in data so you can check for 1s at every index
    for i in zip(*[data[v] for v in value]): 
        if any(i): #checking if any of them have a 1. 
            output += 1
    res[key] = output

timeit 结果:

新代码:6.36 µs ± 115 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

有问题的代码(基准基准):19.8 µs ± 339 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

【讨论】:

  • 出于好奇,为什么在 zip(*[data[v] for v in value]) 行中添加 *?它到底做了什么。
  • 这是解压缩 3 个(或许多/很少)列表的部分,以便您可以正确压缩它们。 zip 需要像 zip(list1,list2,list3) 这样的列表,但我们不知道需要多少个列表,因为它不是恒定的。 zip([list1,list2,list3]) 不会为您做任何事情。于是有了小星星。 @帕拉夫帕特尔
【解决方案2】:

根据我的评论,有几个部分可以简化:

而不是

for k,v in temp_dict.items():
    total = 0
    for t in temp_dict[k]:
        total = total + t
    output_dict[k] = total

你可以写:

output_dict = {k: sum(v) for k,v in temp_dict.items()}

而不是

for key, value in input_dict.items():
    for v in value:
        for j , d in enumerate(data[v]):
            temp_dict[key][j] = max( temp_dict[key][j] , d  )

你可以写:

for key, value in input_dict.items():
    temp_dict[key] = [max(data[v][index] for v in value) for index in range(7)]

然后您可以考虑将所有内容结合起来并达到:

output_dict = {k: sum(max(data[key][index] for key in keys) for index in range(7)) for k, keys in input_dict.items()}

【讨论】:

  • [max(data[v][index] for v in value) for index in range(7)] - 这是理解还是生成器?我正在尝试运行并理解它,看起来它是生成器。你能解释一下这个语法吗?
  • 我想,我明白了。我替换了 max 并将括号从 ( ) 更改为 [ ],它给了我数据字典值的列表。而 max 用于从小的子列表中找到最大的结果。如果我的理解不正确,请纠正我。
  • max(data[v][index] for v in value) 这里传递给max 的表达式是一个生成器。 [max ... for index in range(7)] 这是一个列表理解([] 是这里的线索)
【解决方案3】:
from collections import defaultdict

input_dict = { 'all_val' : ['a', 'b', 'c' ],
               '2nd_group' : ['a', 'b'] ,
               '3rd_grp' : ['a' , 'c']}
data = {  
'a' :      [1,0,1,0,0,0,1],
'b' :      [0,0,1,1,0,1,0],
'c' :      [0,1,1,0,0,0,1]    }

# {'2nd_group': 5, '3rd_grp': 4, 'all_val': 6}

temp_dict = defaultdict(list)

SIZE_OF_LIST = 7

data_keys = data.keys()

# we're basically constructiing the temp_dict on the fly by iterating throug the X and Y axis of the matrix
for i in range(SIZE_OF_LIST):  # i is in X axis of the matrix and represents the columns in this case
    for group, group_items in input_dict.items():  # for each column we iterate over the Y axis (a, b, c)

        # we then need to obtain all the values on a column (the actual 0's and 1's) and create a
        # list from it. In this list we take only does rows that are of interest for us
        # For example, for 2nd_group (a, b), considering that we are on column 0 the resulting list
        # will be generated by getting the values for 'a' and 'b', hence we will have [1, 0]
        data_values = [data[data_key][i] for data_key in group_items]  # thanks to list comprehensions

        # we then need to evaluate the previously created list with the any
        # any(data_vaues) is actually any([1, 0]) (from the previous example)
        # which yelds 1, because there is at least one value with the value 1
        # the resulting value is added at the right position in the temp_dict
        temp_dict[group].append(1 if any(data_values) else 0)

output_dict = {}
for group, elements in temp_dict.items():
    # we just iterate over the temp_dict one more time and create the 
    # sums for all our groups (all_val, 2nd_group, 3rd_group)
    # and add up all the 1's in the list. 
    # For example if we're on '2nd_group' then it's basically a sum(temp_dict['2nd_group'])
    # which yields your desired result
    output_dict[group] = sum(elements)

print output_dict

【讨论】:

  • 您可以考虑添加 cmets 并解释您改进的地方和原因
【解决方案4】:

您可以使用 OR 逻辑操作如下:

import numpy as np
output = {}
for key in input_dict:
    r = []
    for data_key in data:
        if data_key in input_dict[key]:
            if len(r) == 0:
                r = np.asarray(data[data_key])
            else:
                r = r | np.asarray(data[data_key])
    output[key] = list(r).count(1)
print output

【讨论】:

    【解决方案5】:

    我的方法使用七个元素并行计算列表中的所有项目,并且不需要像 numpy 那样单独安装项目。在 Python 3 中是这样写的:

    import operator
    import functools
    
    input_dict = { 'all_val' : ['a', 'b', 'c' ],
                   '2nd_group' : ['a', 'b'] ,
                   '3rd_grp' : ['a' , 'c']}
    data = {
        'a' : 0b1010001,
        'b' : 0b0011010,
        'c' : 0b0110001}
    
    def num_bits(n):
        result = 0
        while n > 0:
            result += n & 1
            n >>= 1
        return result
    
    if __name__ == '__main__':
        result = {}
        for inkey, labels in input_dict.items():
            result[inkey] = num_bits(functools.reduce(operator.__or__, (data[l] for l in labels)))
        print(result)
    

    完全冒险的人甚至可以用字典理解代替主要部分:

    print({inkey: num_bits(functools.reduce(operator.__or__, (data[l] for l in labels))) for inkey, labels in input_dict.items()})
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多