嵌套循环避免自我和相互比较

时间:2017-07-04 11:46:38

标签: python nested-loops hamming-distance

由于这一点非常常见,我想知道以下是否有任何预先存在的解决方案。

假设我有一组 N 字符串,我计算它们之间距离的距离。在这种情况下,它是一个汉明距离,但这并不重要。

如果我想尽快做到这一点,我会避免自我比较:

 def hamming_distance(string1, string2):
     """Return the Hamming distance between equal-length sequences"""
     if len(string1) != len(string2):
         raise ValueError("Undefined for sequences of unequal length")
     return sum(ch1 != ch2 for ch1, ch2 in zip(s1, s2))


ratios=[]
 for a, i in enumerate(string_list):
     for b, j in enumerate(string_list):
         if a == b: # Avoid self comparisons for speed
             break
     ratios.append(hamming_distance(string_list[i], string_list[j]))
 return ratios

但由于这是“对称的”,我还可以抛弃任何相互比较,如果字符串很多和/或很大,这会增加速度。

在上面的设置中是否有一种普遍接受/优雅的方式?

我也知道一般情况下建议避免使用嵌套循环,因为它们可能很慢 - 所以如果有更好的方法可以在列表上实现这种成对迭代(可能是collections中的某些内容?)并且避免自我和相互比较,我都是耳朵。

2 个答案:

答案 0 :(得分:2)

您可以将的嵌套限制为从下一个项目开始到外部循环中的当前项目。这样,您只能浏览每个唯一的一次:

for i, s1 in enumerate(string_list):
   for s2 in string_list[i+1:]:
      ratios.append(hamming_distance(s1, s2))
return ratios

你可以把它放在一个列表comp。:

ratios = [(s1, s2, hamming_distance(s1, s2)) for i, s1 in enumerate(string_list) 
                                                     for s2 in string_list[i+1:]]

你可以把字符串作为结果的一部分放在元组中,就像我在list comp中所做的一样。

答案 1 :(得分:2)

您正在寻找的内容由itertools.combinations()实施。

>>> import itertools
>>> a = [1,2,3]
>>> list(itertools.combinations(a, 2))
[(1, 2), (1, 3), (2, 3)]

所以在你的情况下,它看起来像:

for a, b in itertools.combinations(string_list, 2):
    ratios.append(hamming_distance(a, b))