python - 优化两个列表之间的比较,给出不同的索引

标签 python list optimization

我有三个列表:旧的、新的和忽略的。 old 和 new 是字符串列表。 ignore 是一个索引列表,如果它们不匹配则应该忽略这些索引。目标是创建一个不同且未被忽略的索引列表。

旧的和新的可能包含不同数量的元素。如果新旧之间的尺寸存在差异,则应将差异标记为不匹配(除非被忽略)。

我目前的功能如下:

def CompareFields( old, new, ignore ):
  if ( old == None ):
    if ( new == None ):
      return [];
    else:
      return xrange( len(new) )
  elif ( new == None ):
    return xrange( len(old) )

  oldPadded = itertools.chain( old, itertools.repeat(None) )
  newPadded = itertools.chain( new, itertools.repeat(None) )
  comparisonIterator = itertools.izip( xrange( max( len(old ) , len( new ) ) ), oldPadded, newPadded )
  changedItems = [ i for i,lhs,rhs in comparisonIterator if lhs != rhs and i not in ignore ]
  return changedItems

我尝试过的各种选项的时间给出了以下 100,000 次运行的时间:

[4, 9]
CompareFields: 6.083546
set([9, 4])
Set based: 12.594869
[4, 9]
Function using yield: 13.063725
[4, 9]
Use a (precomputed) ignore bitmap: 7.009405
[4, 9]
Use a precomputed ignore bitmap and give a limit to itertools.repeat(): 8.297951
[4, 9]
Use precomputed ignore bitmap, limit padding and itertools.starmap()/operator.ne(): 11.868687
[4, 9]
Naive implementation: 7.438201

我拥有的最新版本的 python 是 2.6(它是 RHEL5.5)。我目前正在编译 Pypy 来尝试一下。

那么有没有人知道如何让这个函数运行得更快?是否值得使用 Cython?

如果我不能让它运行得更快,我会考虑用 C++ 或 Java 重写整个工具。

编辑:

好的,我为各种答案计时:

[4, 9]
CompareFields: 5.808944
[4, 9]
agf's itertools answer: 4.550836
set([9, 4])
agf's set based answer, but replaced list expression with a set to avoid duplicates: 9.149389
agf's set based answer, as described in answer: about 8 seconds
lucho's set based answer: 10.682579

因此 itertools 似乎是目前的最佳选择。令人惊讶的是,基于集合的解决方案表现如此糟糕。尽管我对使用 lambda 速度较慢并不感到惊讶。

编辑:Java 基准测试 简单的实现,有太多的 if 语句:128 毫秒

最佳答案

对于这两种解决方案,您应该:

ignore = set(ignore)

这会给你恒定的(平均)时间 in 测试。

我认为这是您正在寻找的基于 itertools/zip 的方法:

[i for i, (o, n) in enumerate(izip_longest(old, new)) 
                          if o != n and i not in ignore]

不需要 chain/repeat 来填充——这就是 izip_longest 的用途。 enumerate 也比 xrange 更合适。

还有 Lucho 的回答中 filter/set difference 方法的更 Pythonic(可能更快)版本:

[i for i, v in set(enumerate(new)).symmetric_difference(enumerate(old)) 
                                                     if i not in ignore]

lambda 上,列表理解优于 filtermap,并且不需要将两个列表都转换为 set 如果您使用 symmetric_difference 方法而不是 ^/xor 运算符。

关于python - 优化两个列表之间的比较,给出不同的索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7974883/

相关文章:

python - 你如何计算百分比?

python - 如何不反转十进制数?

list - 如何在 DynamicJasper 中设置 list<String> 的值

python - 分配如何与列表切片一起使用?

OpenGL 交错索引数组

python - 导入 JSON 时使用 Python 脚本中的变量

python - 在python中执行linux时间命令

Python - 基于范围的子列表选择的补充

c++ - openMP过度同步

python - 测试在循环内不会改变的条件