在Python中线性化列表的最短方法

时间:2014-02-26 09:57:25

标签: python algorithm list dictionary

我想从列表中使用线性增加的值创建一个列表,其中Python中的值非线性增加。例如

input =[10,10,10,6,6,4,1,1,1,10,10]

应转换为:

output=[0,0,0,1,1,2,3,3,3,0,0]

我的代码使用python字典

def linearize(input):
    """
    Remap a input list containing values in non linear-indices list
    i.e.
    input = [10,10,10,6,6,3,1,1]
    output= [0,0,0,1,1,2,3,3] 
    """
    remap={}
    i=0
    output=[0]*len(input)
    for x in input:
        if x not in remap.keys():
            remap[x]=i
            i=i+1
    for i in range(0,len(input)):
        output[i]=remap[input[i]]
    return output

但我知道这段代码可以更有效率。 Numpy是一个选择,有些想法可以更好地以更加pythonic的方式完成这项任务吗? 必须在大名单上频繁调用此函数。

4 个答案:

答案 0 :(得分:5)

根据your comment in the question,您正在寻找类似这样的内容

data = [8,8,6,6,3,8]
from itertools import count
from collections import defaultdict
counter = defaultdict(lambda x=count(): next(x))
print([counter[item] for item in data])
# [0, 0, 1, 1, 2, 0]

Thanks to poke

list(map(lambda i, c=defaultdict(lambda c=count(): next(c)): c[i], data))

现在它只是一个班轮:)

答案 1 :(得分:2)

使用collections.OrderedDict

In [802]: from collections import OrderedDict
     ...: odk=OrderedDict.fromkeys(l).keys()
     ...: odk={k:i for i, k in enumerate(odk)}
     ...: [odk[i] for i in l]
Out[802]: [0, 0, 0, 1, 1, 2, 3, 3, 3]

答案 2 :(得分:1)

没有导入的更简单的解决方案:

input =[10,10,10,6,6,4,1,1,1,10,10]
d = {}
result = [d.setdefault(x, len(d)) for x in input]

答案 3 :(得分:0)

我使用numpy来实现这个功能,当输入列表非常像2,000,000个元素时,我的测试工作速度比你的快。

import numpy as np
def linearize(input):
    unique, inverse = np.unique(input, return_inverse=True)
    output = (len(unique)-1) - inverse
    return output

此外,此功能仅在您的输入处于降序时才会起作用。 如果有帮助,请告诉我。