【问题标题】:Python optimize how to find duplicate value and value index in a listPython优化如何在列表中查找重复值和值索引
【发布时间】:2015-04-19 18:11:28
【问题描述】:

我有一个包含 18 000 个唯一 ID 的列表。 ID 是字母A, B, C, D 的串联。 我制作了一个代码,将 ID 按ID[0:-1] 分组并给出重复 ID 的索引位置。

这很好用,但要继续很长时间:在 110 secs 附近,对于 18 000 ID。 你有想法加速我的代码吗?

a = ['1CDABCABDA', '1CDABCABDB', '1CDABCABDD', '1BCABCCCAA', '1DDAABBBBA', '1BCABCCCAD']

startTime = time.time()
b = [i[0:-1] for i in a]
b = list(set(b))


result = range(len(b))
it = 0
for i in result:
    result[i] = [b[i], []]
    for j in xrange(len(a)):
        if b[i] == a[j][0:-1]:
            result[i][1].append(j)

endTime =  time.time()

print endTime - startTime, 'secs !'

输出:

>>> [['1CDABCABD', [0, 1, 2]], ['1DDAABBBB', [4]], ['1BCABCCCA', [3, 5]]]

【问题讨论】:

  • 你能显示你的代码的输出吗?
  • >>> [['1CDABCABD', [0, 1, 2]], ['1DDAABBBB', [4]], ['1BCABCCCA', [3, 5]]]跨度>
  • 你需要解释更多关于你的代码和输出,例如['1DDAABBBB', [4]]中的4是什么?
  • 是a中的索引位置

标签: python performance list optimization duplicates


【解决方案1】:

作为解决此类问题的更 Pythonic 方式,请使用 collections.defaultdict

>>> from collections import defaultdict
>>> d=defaultdict(list)
>>> new=[i[:-1] for i in a]

>>> d=defaultdict(list)
>>> for i,j in enumerate(new):
...    d[j].append(i)
... 
>>> d
defaultdict(<type 'list'>, {'1CDABCABD': [0, 1, 2], '1DDAABBBB': [4], '1BCABCCCA': [3, 5]})
>>> d.items()
[('1CDABCABD', [0, 1, 2]), ('1DDAABBBB', [4]), ('1BCABCCCA', [3, 5])]

注意defaultdict 是一个线性解,比itertools.groupbysorted 更有效。

你也可以使用dict.setdefault 方法:

>>> d={}
>>> for i,j in enumerate(new):
...   d.setdefault(j,[]).append(i)
... 
>>> d
{'1CDABCABD': [0, 1, 2], '1DDAABBBB': [4], '1BCABCCCA': [3, 5]}

有关更多详细信息,请查看以下基准标记它 ~4X 更快:

s1="""
from itertools import groupby
a = ['1CDABCABDA', '1CDABCABDB', '1CDABCABDD', '1BCABCCCAA', '1DDAABBBBA', '1BCABCCCAD']
key = lambda i: a[i][:-1]
indexes = sorted(range(len(a)), key=key)
result = [[x, list(y)] for x, y in groupby(indexes, key=key)]
"""
s2="""
a = ['1CDABCABDA', '1CDABCABDB', '1CDABCABDD', '1BCABCCCAA', '1DDAABBBBA', '1BCABCCCAD']
new=[i[:-1] for i in a]
d={}
for i,j in enumerate(new):
   d.setdefault(j,[]).append(i)
d.items()
    """


print ' first: ' ,timeit(stmt=s1, number=100000)
print 'second : ',timeit(stmt=s2, number=100000)

结果:

 first:  0.949549913406
second :  0.250894069672

【讨论】:

  • 18 000 ID 0.11 秒!
  • @Guilhain 所以请随意并接受答案;)
  • s2 是我使用 18 000 id 进行 10 000 次迭代的最佳解决方案,timeit 需要 16.46 秒。恭喜!
【解决方案2】:

这就是 groupby 在 python 中的有效作用:

from itertools import groupby
a = ['1CDABCABDA', '1CDABCABDB', '1CDABCABDD', '1BCABCCCAA', '1DDAABBBBA', '1BCABCCCAD']
key = lambda i: a[i][:-1]
indexes = sorted(range(len(a)), key=key)
result = [[x, list(y)] for x, y in groupby(indexes, key=key)]

输出:

[['1BCABCCCA', [3, 5]], ['1CDABCABD', [0, 1, 2]], ['1DDAABBBB', [4]]]

【讨论】:

  • @Guilhain 也试试 Kasra 的解决方案
【解决方案3】:

不使用其他模块的替代解决方案:

grouped = {}
for i, j in enumerate(a):    
    itm = grouped.get(j[0:-1], [])
    itm.append(i)    
    grouped[j[0:-1]] = itm

print [[k, v] for k, v in grouped.items()] # [['1CDABCABD', [0, 1, 2]], ['1DDAABBBB', [4]], ['1BCABCCCA', [3, 5]]]

【讨论】:

  • 0.05 秒!非常感谢!
  • @Guilhain 喜欢的请举手,拍两下,点赞采纳! :D
  • 等等,但您需要返回索引...只是技术性问题...但不知道时间会受到怎样的影响...
  • @JuniorCompressor 你是说print grouped.keys() 吗?
  • 你应该像[['1CDABCABD', [0, 1, 2]]...这样返回
【解决方案4】:

你在找这个吗:

>>> d = {}
>>> for ind, elem in enumerate(a):
    ... d.setdefault(elem[0:-1], []).append(ind)
>>> print d
{'1CDABCABD': [0, 1, 2], '1DDAABBBB': [4], '1BCABCCCA': [3, 5]}

该解决方案与 Kasra 的优化代码非常相似,但运行速度稍快。不同之处在于切片的位置,但不确定为什么其中一个的性能略好于另一个:

s1 = """
a = ['1CDABCABDA', '1CDABCABDB', '1CDABCABDD', '1BCABCCCAA',
      '1DDAABBBBA', '1BCABCCCAD']
d = {}
for ind, elem in enumerate(a):
    d.setdefault(elem[0:-1], []).append(ind)
"""

s2="""
a = ['1CDABCABDA', '1CDABCABDB', '1CDABCABDD', '1BCABCCCAA', '1DDAABBBBA', '1BCABCCCAD']
new=[i[:-1] for i in a]
d={}
for i,j in enumerate(new):
   d.setdefault(j,[]).append(i)
"""

print 'Kasra's time/my time: %s' % (str(timeit(stmt=s2, number=100000)/timeit(stmt=s1, number=100000))

Kasra's time/my time: 1.24058060531 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-19
    • 2012-07-16
    • 2021-12-17
    • 1970-01-01
    • 2020-02-13
    • 1970-01-01
    • 2019-10-26
    相关资源
    最近更新 更多