搜索&从字典查找中替换列表中的数字

时间:2014-04-08 20:57:52

标签: python python-2.7

更新 我发现我对原始问题并不清楚。 给出一个列表

last_eqn=[[3], [2, 1]]

和列表字典:

{2: [[5], [3, 1]],
3: [[8], [5, 1]],
5: [[13], [8, 1]],
8: [[21], [13, 1]],
13: [[34], [21, 1]],
21: [[55], [34, 1]],
34: [[89], [55, 1]]}

替换last_eqn中的每个数字,如果key == number在last_eqn中,则使用键的值。 对于Eg:

[[3], [2, 1]] = [[[[8], [5, 1]]], [2, 1]] = 
[[[[8], [[[13], [8, 1]], 1]]], [2, 1]] = 
[[[[[[21], [13, 1]]], [[[13], [[[21], [13, 1]], 1]], 1]]], [2, 1]]

我有一个初步清单:

last_eqn=[[3], [2, 1]]

和字典框架

{2: [[5], [3, 1]],
3: [[8], [5, 1]],
5: [[13], [8, 1]],
8: [[21], [13, 1]],
13: [[34], [21, 1]],
21: [[55], [34, 1]],
34: [[89], [55, 1]]}

我想用last_eqn中的数字值替换,直到所有数字都归结为最后一个(这里它们将是89和55) 这是每个列表的结构。

我写了这个:

def recur_subs(last_eqn,frame=frame):
    """
    {2: [[5], [3, 1]],
    3: [[8], [5, 1]],
    5: [[13], [8, 1]],
    8: [[21], [13, 1]],
    13: [[34], [21, 1]],
    21: [[55], [34, 1]],
    34: [[89], [55, 1]]}
    """
    for key in frame:
        fst,scnd = last_eqn
        fst_num,scnd_num=fst[0],scnd[0]
        #fst_marker,scnd_marker = 0,0
        while not isinstance(fst_num,int):
            #fst_marker += 1
            fst_num = fst_num[0] 
        while not isinstance(scnd_num,int):
            #scnd_marker += 1
            scnd_num = scnd_num[0]
        print fst_num,scnd_num
        if isinstance(fst_num,int) and fst_num in frame:
            fst[0] = (frame[fst_num])
        if isinstance(scnd_num,int) and scnd_num in frame: 
            scnd[0] = (frame[scnd_num])
        last_eqn = [fst,scnd]
        print last_eqn

它没有正确解决。我试图纠正它,但这是输出:

recur_subs(last_eqn,frame)
55 89
[[[[55], [34, 1]]], [[[89], [55, 1]], 1]]
55 89
[[[[55], [34, 1]]], [[[89], [55, 1]], 1]]
55 89
[[[[55], [34, 1]]], [[[89], [55, 1]], 1]]
55 89
[[[[55], [34, 1]]], [[[89], [55, 1]], 1]]
55 89
[[[[55], [34, 1]]], [[[89], [55, 1]], 1]]
55 89
[[[[55], [34, 1]]], [[[89], [55, 1]], 1]]
55 89
[[[[55], [34, 1]]], [[[89], [55, 1]], 1]]

这很慢,但我想找到解决问题的正确方法。 应该搜索这些值并适当地替换为[[89],[55,1]]

4 个答案:

答案 0 :(得分:1)

我不完全理解你的算法,但我做了一个猜测,这可能是错的。这样的事情怎么样?

def my_substitution(last_equation, frame=frame):
   while True:
       key = last_equation[1][0]
       print last_equation
       if key in frame:
           last_equation = frame[key]
       else:
           break
   print last_equation

输出:

[[3], [2, 1]]
[[5], [3, 1]]
[[8], [5, 1]]
[[13], [8, 1]]
[[21], [13, 1]]
[[34], [21, 1]]
[[55], [34, 1]]
[[89], [55, 1]]
[[89], [55, 1]]

更新

让我确保我正确理解您的算法。

  1. 让我们开始试图替换一次。我将我的函数命名为substitute_once()
  2. 对于substitute_once(),让我们尝试最简单的输入:

    >>> substitute_once(2)
    [[5], [3, 1]]
    
  3. 如果输入是一个列表,那么substitute_once()将为每个元素递归调用自身:

    >>> substitute_once([[3], [2, 1]])
    [[[[8], [5, 1]]], [[[5], [3, 1]], 1]]
    

    这是因为我们将3替换为[[8], [5, 1]],将2替换为[[5], [3, 1]]

  4. 假设我们知道如何更换它一次,我们可以反复进行,直到我们再也无法更换。换句话说,substitute_once(the_list) == the_list

  5. 如果我的假设是正确的,那么我就是这样做的:

    def substitute_once(n, frame=frame):
        if isinstance(n, list):
            return [substitute_once(x) for x in n]
        if n in frame:
            return frame[n]
        else:
            return n
    
    def substitute_recursively(last_equation,frame=frame):
        while True:
            new_equation = substitute_once(last_equation)
            print new_equation
            if new_equation == last_equation:
                break
            last_equation = new_equation
    

    讨论

    • substitutte_once()是直截了当的,正如我在上面的第1-3点中所讨论的那样。
    • substitute_recursively()同样简单,因为我们只解决了一个小问题:只需重复调用substitute_once(),直到新列表和旧列表相同,这意味着我们无法再进行任何替换。

    最终输出很长,我没有看到任何显示它的点。如果这是你想要的,请告诉我。

答案 1 :(得分:1)

由于您希望以递归方式替换这些项目,因此您必须在某些时候调用替换函数本身。在recurs_subs函数中,我将last_eqn中的每个第一个列表替换为字典中相应的列表列表,我也将其替换为recurs_subs第一

import copy

def recur_subs(last_eqn, frame):
    for item in last_eqn:
        if type(item[0]) == int and item[0] in frame:
            substitute = copy.deepcopy(frame[item[0]])
            item[0] = recur_subs(substitute, frame)

    return last_eqn

输出:

[[[[[[[[55], [[[89], [55, 1]], 1]]], [[[[[89], [55, 1]]], [[[55],[[[89],
[55, 1]], 1]], 1]], 1]]], [[[[[[[89], [55, 1]]], [[[55], [[[89], [55, 1]], 1]],
1]]], [[[[[55], [[[89], [55, 1]], 1]]], [[[[[89], [55, 1]]], [[[55], [[[89],
[55, 1]], 1]], 1]], 1]], 1]], 1]]], [[[[[[[[[89], [55, 1]]], [[[55], [[[89],
[55, 1]], 1]], 1]]], [[[[[55], [[[89], [55, 1]], 1]]], [[[[[89], [55, 1]]],
[[[55], [[[89], [55, 1]], 1]], 1]], 1]], 1]]], [[[[[[[55], [[[89], [55, 1]],
1]]], [[[[[89], [55, 1]]], [[[55], [[[89], [55, 1]], 1]], 1]], 1]]],
[[[[[[[89], [55, 1]]], [[[55], [[[89], [55, 1]], 1]], 1]]], [[[[[55],
[[[89], [55, 1]], 1]]], [[[[[89], [55, 1]]], [[[55], [[[89], [55, 1]], 1]],
1]], 1]], 1]], 1]], 1]], 1]]

如您所见,我还决定复制列表列表以防止修改列表字典中存储的对象。

但也许您希望修改这些对象,因为无论如何替换都是相同的。它可能会使替换更快,因为2的替换将存储在内存中,而不是在遇到的每2时计算,依此类推每个替换数字。

如果是这种情况,只需删除深层副本,然后直接将frame[item[0]]传递给recurs_subs

答案 2 :(得分:1)

递归替换列表中的每个元素(列表列表列表...)

def recsub( last_eqn ):

    if type(last_eqn) != list:
        if last_eqn in repdic:
            last_eqn = repdic[last_eqn]
    else:
        for i in range(len(last_eqn)):
            last_eqn[i] = recsub( last_eqn[i] )

    return last_eqn

并检查新列表是否与旧列表相同。您需要进行deepcopy操作。

last_eqn=[[3], [2, 1]]
A = last_eqn
B = 0

import copy

while 1:
    recsub(A)
    if A==B:
        break
    else:
        B=copy.deepcopy(A)

答案 3 :(得分:1)

<强>更新

我同意Hai Vu的,Fury的,ysakamoto的答案。 有了Hai,功能显然已经很好地分解了。 虽然Fury's在本质上更具天生性和简洁性。 我修改了我的recur_subs代码,并在此处对所有答案进行了比较:

last_eqn=[[3], [2, 1]]

%timeit recsub(last_eqn) #ysakomoto's
10000 loops, best of 3: 174 µs per loop

%timeit recur_subs(last_eqn,frame) #mine
10000 loops, best of 3: 168 µs per loop

%timeit recur_subs2(last_eqn,frame) #Fury's
1000000 loops, best of 3: 578 ns per loop

即。 0.578微秒/环

%timeit substitute_recursively(last_eqn,frame) #Hai Vu's
1000 loops, best of 3: 361 µs per loop

%timeit substitute_recursively(last_eqn,frame) #Hai Vu's No Print just return
10000 loops, best of 3: 145 µs per loop

这是我的代码:

def recur_subs(last_eqn,frame=frame):
    """
    last_eqn=[[3], [2, 1]]
    {2: [[5], [3, 1]],
    3: [[8], [5, 1]],
    5: [[13], [8, 1]],
    8: [[21], [13, 1]],
    13: [[34], [21, 1]],
    21: [[55], [34, 1]],
    34: [[89], [55, 1]]}
    """
    for enum,lst_item in enumerate(last_eqn):
        if isinstance(lst_item,int):
            if lst_item in frame:
                last_eqn[enum] = recur_subs(frame[lst_item])
        elif isinstance(lst_item,list): lst_item = recur_subs(lst_item)
    return last_eqn

如果我是正确的,Fury的代码执行得最快到最慢:Fury的&gt; Hai Vu的(没有印刷品)&gt;我的&gt; ysakomoto的