我想从列表中使用线性增加的值创建一个列表,其中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的方式完成这项任务吗? 必须在大名单上频繁调用此函数。
答案 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]
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
此外,此功能仅在您的输入处于降序时才会起作用。 如果有帮助,请告诉我。