【问题标题】:quickly subset array if values are matched in dictionary in python如果值在python中的字典中匹配,则快速子集数组
【发布时间】:2018-02-13 05:51:13
【问题描述】:

我正在尝试加快此功能。它检查字典中是否存在列表值的总和。例如,如果x 在添加[0, 1][1, 0][0, -1][-1, 0] 后所取的值存在于layout 中,则将其作为选项在输出中删除。例如:

layout = { 0:[2,1], 1:[3,1], 2:[2,2], 3:[6,3] }
x = [2, 1]

possibilities = numpy.zeros(shape=(4,2))
possibilities[0] = [1, 0]
possibilities[1] = [-1, 0]
possibilities[2] = [0, 1]
possibilities[3] = [0, -1]

def myFun(x, layout, possibilities):
    new_possibilities = possibilities + x

    output_direction = []
    for i in new_possibilities:
        i = list(i)
        output_direction.append( (i in layout.values()) )

    output_direction = true_to_false(output_direction)
    possibilities = possibilities[output_direction]
    if possibilities.size == 0:
        possibilities = [0, 0]
        return possibilities
    else:
        return possibilities

# This changes True to False
def true_to_false(y):
output = []
for i in y:
    if i == True:
         output.append((False))
    elif i == False:
        output.append((True))       
return output

如果我现在运行这个函数,我会得到以下输出:

myFun(x, layout, possibilities)

array([[-1.,  0.],
       [ 0., -1.]])

我得到这个输出的原因是因为[0, 0] + x在布局中被[2,1]占据,[0,1] + x在布局中被[2,2]占据,[1,0] + x在布局中被[3,1]占据,而@布局中不存在 987654335@ 和 [0, -1] + x,因此这是输出结果。

这个函数运行良好我只是希望它更快,因为布局可能会变得非常大(数万个项目)并且这个函数已经在 for 循环中运行。

【问题讨论】:

    标签: python numpy dictionary for-loop


    【解决方案1】:

    风格

    请不要说,例如,print((((42)))),当说 print(42) 就足够了。多余的括号使您的代码更难阅读。

    否定

    你的否定函数可以简化为:

    def true_to_false(y):
        return [not b
                for b in y]
    

    但你甚至不需要那个。您可以在追加时使用not 删除函数并避免函数调用的成本:

    output_direction = []
    for i in new_possibilities:
        output_direction.append(list(i) not in layout.values())
    possibilities = possibilities[output_direction]
    ...
    

    即使是冗长的部分,因为它自然适合列表理解:

    output_direction = [list(i) not in layout.values()
                        for i in new_possibilities]
    

    速度

    反复询问i 是否在.values() 范围内的问题在于这是线性扫描。如果len(layout.values()) 变得非常大,您真的想将这些值放入哈希映射中:

    vals = set(layout.values())
    output_direction = [list(i) not in vals
                        for i in new_possibilities]
    

    现在 O(n) 线性扫描变为 O(1) 恒定时间哈希查找。

    如果vals 通常不会在一次 myFun 调用和下一次调用之间发生变化,则考虑将其作为参数与layout 一起传递。顺便说一句,如果调用者愿意传入x + possibilities,您可以省略x 参数。

    您是否考虑过使用集合交集来代替?

    【讨论】:

    • 感谢您的富有洞察力的回复。当我运行 O(1) 解决方案时,我遇到了这个错误:unhashable type: 'list' any idea?
    • 列表是可变的,因此是不可散列的,因为如果内容改变,散列也会改变。元组 OTOH 是不可变的,例如tuple(i) 是有效的键,而 list(i) 不是。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 2021-11-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多