如何改进字典自我搜索比较和合并

时间:2016-07-02 08:30:50

标签: python performance dictionary time

我需要将字典与值进行比较,以找到匹配的所有值并将其添加出来。问题是我有很大的字典,我的代码很慢。有没有更好的方法来做到这一点或改善我的代码时间?

import itertools
import copy

Dic = {
    0: ['-1','A','B','p','r'],
    1: ['-','q','p','r'],
    2: ['-1','K','q','p','r'],
    3: ['+','q','p','r'],
    4: ['1','B','q','p','r'],
    5: ['-','K','q','p','r'],
}

def S_Sing(SX_Sing,SY_Sing):
       if SX_Sing=='+' or SX_Sing=='-':
          XX_L=[SX_Sing]
       elif SX_Sing!='+' or SX_Sing!='-':
          XX_L=SX_Sing
       if SY_Sing=='+' or SY_Sing=='-':
          YY_L=[SY_Sing]
       elif SY_Sing!='+' or SY_Sing!='-':
          YY_L=SY_Sing    
       if XX_L==['+'] or XX_L==['-']:
             XX_L.append('1')
       if YY_L==['+'] or YY_L==['-']:
             YY_L.append('1')            
       Final=int(''.join(XX_L))+int(''.join(YY_L))
       Sum_Final=str(Final)
       return Sum_Final 


def Comp_Dict_Itself(DicX1):
        D_itself_F={}
        D_clone= copy.deepcopy(DicX1) 
        Dic_to_Lista=[]

        for k,v in D_clone.iteritems():
          Dic_to_Lista.append(v)
        for a, b in itertools.combinations(Dic_to_Lista, 2):
          if a[:1]!='0' and b[:1]!='0' :
            if a[1:]==b[1:]:

                S_Final=S_Sing(a[:1],b[:1]) 
                if S_Final==0:
                    b[:]='0'
                    a[:]='0'
                if S_Final!=0:
                    b[0]='0'
                    a[0]=S_Final    


        somelist_F = [x for x in Dic_to_Lista if x[0]!='0']
        for pos, item in enumerate(somelist_F ):  
            if item[0]!='0':
                D_itself_F[pos]= item 
        return D_itself_F

print(Comp_Dict_Itself(Dic))

输出:

{0: ['-1', 'A', 'B', 'p', 'r'], 1: ['-2', 'K', 'q', 'p', 'r'], 2: ['1', 'B', 'q', 'p', 'r']}

代码所做的是首先检查每个值,以便添加v[1:]值对于考虑的密钥需要相同的值。键A和B. v[0]只是一个常量,表示列表重复的次数。然后v[0]取决于其符号和值,将添加或减去例如vA[0]='1'vA[0]='+'以及vB[0]='-1'vB[0]='-'则新vA[0]vB[0]将为0,但如果vA[0]=1 }和vB[0]=1然后新值将为vA[0]=2vB[0]=0。然后,将删除值为0的键

2 个答案:

答案 0 :(得分:0)

好的,我试图了解你的代码,看起来你正在做相当于以下的事情,我希望它更简单,更清晰,至少更有效率:

import itertools as it


def sign_to_num(val):
    if val == '+':
        return 1
    elif val == '-':
        return -1
    return int(val)


def item_sum(left_val, right_val):
    return sign_to_num(left_val) + sign_to_num(right_val)


def comp_dict_itself(d):
    values = [list(v) for v in d.values()]
    for a, b in it.combinations(values, 2):
        if a[0] != '0' != b[0] and a[1:] == b[1:]:
            a[0] = str(item_sum(a[0], b[0]))
            b[0] = '0'

    return dict(enumerate(v for v in values if v[0] != '0'))

注意:

  • 代码中的比较:if a[:1] != '0' and b[:1] != '0'没用,因为条件始终为true。这是因为ab是两个list,所以a[:1] == ['0']a[:1] == ['+']。在每种情况下,它们都与str不同。

    我已将其更改为a[0] != '0' and b[0] != '0',可以简化为a[0] != '0' != b[0]

  • 使用带有整数键的dict没有意义,特别是如果这些键是连续的。您只需使用list

  • 即可
  • dict未被排序,因此values列表不需要具有与键值对应的顺序。

  • 无需先使用deepcopy创建新的dict,然后提取值列表。了解我如何构建values

答案 1 :(得分:0)

我玩这个代码并使用之前的答案我找到了一个更快的解决方案:

def sign_to_num(val):
if val == '+':
    return 1
elif val == '-':
    return -1
return int(val)


def item_sum(left_val, right_val):
    return sign_to_num(left_val) + sign_to_num(right_val)


def comp_dict_itself2(d):
    values = [list(v) for v in d.values()]
    results = {}
    for item in values:
        key = (" ".join(str(x) for x in item[1:])) #Dict_A_R[]=
        if key in results: 
            results[key][0]= str(item_sum(results[key][0], item[0]))
        else:   
            results[key] = item
    DicFinal={}
    for pos, item in enumerate(results ):  
                 DicFinal[pos]= results [item] 
    return DicFinal

前两个函数来自Bakuriu的解决方案新的comp_dict_itself2函数使用创建字典并添加找到的重复次数。

对于我正在运行的词典,这些是个人资料:

  ncalls  tottime  percall  cumtime  percall filename:lineno(function)

   18   58.947    3.275   59.045    3.280 Test_a.py:666(comp_dict_itself)

   18    0.193    0.011    0.491    0.027 Test_a.py:675(comp_dict_itself2)