实时连续两次使用项目之间的不同项目数

时间:2015-01-26 14:49:07

标签: python performance algorithm

我正在处理找到距离的问题 - 实时连续两次使用项目之间的不同项目数。输入是从一个大文件(~10G)中读取的,但为了说明,我将使用一个小列表。

from collections import OrderedDict
unique_dist = OrderedDict()
input = [1, 4, 4, 2, 4, 1, 5, 2, 6, 2]

for item in input:
    if item in unique_dist:
        indx = unique_dist.keys().index(item) # find the index
        unique_dist.pop(item)                 # pop the item
        size = len(unique_dist)               # find the size of the dictionary
        unique_dist[item] = size - indx       # update the distance value
    else:
        unique_dist[item] = -1                # -1 if it is new
print input
print unique_dist

正如我们所看到的,对于每个项目,我首先检查项目是否已经存在于字典中,如果是,我更新距离的值,否则我将其插入到末尾,值为-1。问题是随着规模变大,这似乎效率很低。内存不是问题,但pop函数似乎是。我这样说是因为,如果我这样做的话:

for item in input:
        unique_dist[item] = random.randint(1,99999)

程序运行得非常快。我的问题是,有什么方法可以让我的程序更高效(快速)?

编辑:

似乎真正的罪魁祸首是indx = unique_dist.keys().index(item)。当我用indx = 1替换它时。该计划的速度提高了几个数量级。

3 个答案:

答案 0 :(得分:1)

根据我对cProfile模块所做的简单分析,到目前为止最昂贵的操作是OrderedDict.__iter__()OrderedDict.keys()

以下实施的速度大约是您的7倍(根据我所做的有限测试)。

  • 通过维护项目列表unique_dist.keys()来避免对keys的调用。我不完全确定,但我认为这也避免了对OrderedDict.__iter__()的调用。
  • 通过在必要时递增len(unique_dist)变量来避免调用size。 (我不确定操作len(OrderedDict)的成本是多少,但无论如何)
def distance(input):
    dist= []
    key_set= set()
    keys= []
    size= 0
    for item in input:
        if item in key_set:
            index= keys.index(item)
            del keys[index]
            del dist[index]
            keys.append(item)
            dist.append(size-index-1)
        else:
            key_set.add(item)
            keys.append(item)
            dist.append(-1)
            size+= 1
    return OrderedDict(zip(keys, dist))

答案 1 :(得分:0)

我修改了@Rawing的答案,以克服set数据结构所占用的查找和插入时间所带来的开销。

from random import randint
dist = {}
input = []
for x in xrange(1,10):
    input.append(randint(1,5))
keys = []
size = 0
for item in input:
    if item in dist:
        index = keys.index(item)
        del keys[index]
        keys.append(item)
        dist[item] = size-index-1
    else:
        keys.append(item)
        dist[item] = -1
        size += 1
print input
print dist

答案 2 :(得分:-1)

这个怎么样:

from collections import OrderedDict
unique_dist = OrderedDict()
input = [1, 4, 4, 2, 4, 1, 5, 2, 6, 2]

for item in input:
    if item in unique_dist:
        indx = unique_dist.keys().index(item)
        #unique_dist.pop(item)                # dont't pop the item
        size = len(unique_dist)               # now the directory is one element to big
        unique_dist[item] = size - indx - 1   # therefor decrement the value here
    else:
        unique_dist[item] = -1                # -1 if it is new
print input
print unique_dist

[1, 4, 4, 2, 4, 1, 5, 2, 6, 2]
OrderedDict([(1, 2), (4, 1), (2, 2), (5, -1), (6, -1)])

请注意unique_dist中的条目现在按输入中第一次出现的项目排序;你的最后一次订购是由你订购的:

[1, 4, 4, 2, 4, 1, 5, 2, 6, 2]
OrderedDict([(4, 1), (1, 2), (5, -1), (6, -1), (2, 1)])