假设我有一个这样的列表:
newIndexVertList = [0, 1, 2, 2, 1, 20, 21, 21, 20, 3, 23, 22]
我想将其转换为:
newIndexVertList = [0, 1, 2, 2, 1, 4, 5, 5, 4, 3, 7, 6]
此处,转换基于原始列表中按升序排列的数字位置。因此,在新的列表中,数字将根据逻辑替换:
0 --> 0 0th position in sorted list
1 --> 1 1st position in sorted list
2 --> 2 2nd position in sorted list
3 --> 3 3rd position in sorted list
20 --> 4 4th position in sorted list
21 --> 5 5th position in sorted list
22 --> 6 6th position in sorted list
23 --> 7 7th position in sorted list
以下是我的代码:
c = 0
for i in xrange(len(newIndexVertList)):
if c < newIndexVertList[i]:
newIndexVertList[i] = c
c += 1
continue
elif c == newIndexVertList[i]:
c += 1
continue
else:
continue
# actual output: [0, 1, 2, 2, 1, 3, 4, 5, 6, 3, 7, 8]
# expected output: [0, 1, 2, 2, 1, 4, 5, 5, 4, 3, 7, 6]
我的代码有什么问题?实现这一目标的优雅方式是什么?
由于我的顶点列表将在100k范围内,我正在寻找最快的执行。
答案 0 :(得分:7)
您可以通过创建中间dict
对象来实现该目标,以使用sorted()
和set()
使用enumerate()
将数字与其在原始列表中的位置进行映射:
>>> my_list = [0, 1, 2, 2, 1, 20, 21, 21, 20, 3, 23, 22]
>>> num_map = {j: i for i, j in enumerate(sorted(set(my_list)))}
# ^ ^ to get unique elements
# ^ sort numbers in ascending order
>>> [num_map[n] for n in my_list]
[0, 1, 2, 2, 1, 4, 5, 5, 4, 3, 7, 6]
list(map({j: i for i, j in enumerate(sorted(set(my_list)))}.get, my_list))
# ^ type-cast `map` object to `list` for Python 3.x compatibility
答案 1 :(得分:3)
您在评论中提到您的数据很大(100k)并且您正在寻找最快的执行。你应该考虑使用numpy:
>>> vertices = [0, 1, 2, 2, 1, 20, 21, 21, 20, 3, 23, 22]
>>> np.unique(vertices, return_inverse=True)[1]
array([0, 1, 2, 2, 1, 4, 5, 5, 4, 3, 7, 6])
对于随机分布在0到100之间的100k长整数数组,这比当前接受的答案快3倍以上。
Python聊天室中用户DSM建议的另一个高性能选项是使用scipy.stats
对数据进行排名:
>>> import scipy.stats
>>> (scipy.stats.rankdata(vertices, 'dense') - 1).astype(int)
array([0, 1, 2, 2, 1, 4, 5, 5, 4, 3, 7, 6])