嵌套for循环需要可能的优化

时间:2014-10-26 16:50:43

标签: python list-comprehension

我有两个用户列表(users1和users2),我将它们与以下代码进行比较:

def lev(seq1, seq2):
    oneago = None
    thisrow = range(1, len(seq2) + 1) + [0]
    for x in xrange(len(seq1)):
        twoago, oneago, thisrow = oneago, thisrow, [0] * len(seq2) + [x + 1]
        for y in xrange(len(seq2)):
            delcost = oneago[y] + 1
            addcost = thisrow[y - 1] + 1
            subcost = oneago[y - 1] + (seq1[x] != seq2[y])
            thisrow[y] = min(delcost, addcost, subcost)
    return thisrow[len(seq2) - 1]

for x in users1_list:
    for y in users2_list:
        if 3 >= lev(x,y) > 1:
            print x, "seems a lot like", y

我可以使用list-comprehension来改进嵌套的for循环吗?

2 个答案:

答案 0 :(得分:0)

>>> list1 = ['Bret', 'Jermaine', 'Murray']
>>> list2 = ['Jermaine', 'Murray', 'Mel']

如果列表中的条目是唯一的,则将它们转换为集合可能是有意义的。然后你可以看到哪些是常见的东西:

>>> set(list1).intersection(set(list2))
{'Jermaine', 'Murray'}

可以返回两个集合的并集:

>>> set(list1).union(set(list2))
{'Bret', 'Jermaine', 'Mel', 'Murray'}

要衡量两组之间的通用性,您可以计算Jaccard索引(有关详细信息,请参阅http://en.wikipedia.org/wiki/Jaccard_index):

>>> len(set(list1).intersection(set(list2))) / float(len(set(list1).union(set(list2))))
0.5

这是常见元素的数量除以元素总数。

答案 1 :(得分:0)

您可以使用列表推导来改进嵌套for循环吗?

lev函数中,我不这么认为 - 至少不是“这是坏的,列表理解是清除它的自然而直接的东西”。

是的,你可以在那里使用列表理解,但有几个因素反对理解:

  1. 你在计算很多东西。这意味着结果表达式(或子表达式)需要许多字符。这将是一个非常长的理解表达,使质量格式化变得困难,并且使得难以同时保持头脑中的所有碎片。

  2. 您已经很好地命名了具有逻辑意义的子表达式组件。分散到多个语句中,代码清楚地表明如何计算删除,添加和变电站成本。真好。它有助于理解,尤其是对于您或其他在一段时间后回到此代码的人,并且必须再次理解它。如果你缩短为长表达式以使列表理解变得整洁,那么你将删除那些子表达式的清晰度。

  3. 你做了很多索引。这通常是Python中的反模式/不良实践,它具有良好的“迭代循环项”功能。但是有算法 - 这似乎是其中之一 - 索引是明确的访问方法。它与您在其他来源或参考资料中的类似程序中所发现的内容非常一致。因此,使用更原始的索引方法 - 在许多Python上下文中通常没有意义的方法 - 在这里工作得非常好。

  4. 在第二部分中,您可以循环遍历项目而不是整齐的索引,您可以这样做。这并不像你想要避免使用Pythonic构造。

  5. 虽然在此功能期间它似乎是一个常数,但我确实一直在重新计算len(seq2)。我会计算一次并重复使用存储的值。你真的使用twoago吗?我没有看到它。所以修改后的代码片段可能是:

    def lev(seq1, seq2):
        oneago = None
        len2 = len(seq2)
        thisrow = range(1, len2 + 1) + [0]
        for x in xrange(len(seq1)):
            oneago, thisrow = thisrow, [0] * len2 + [x + 1]
            for y in xrange(len2):
                delcost = oneago[y] + 1
                addcost = thisrow[y - 1] + 1
                subcost = oneago[y - 1] + (seq1[x] != seq2[y])
                thisrow[y] = min(delcost, addcost, subcost)
        return thisrow[len2 - 1]
    

    最后,stackoverflow往往与问题有关。它有一个姊妹网站codereview,可能更适合详细的代码改进建议(就像programmers更适合更多理论编程问题)。