我正在编写一个函数,它接受一个整数列表并返回一个相对定位元素的列表。
也就是说,如果我对所述函数的输入是 [1,5,4] ,那么输出将是 [0,2,1] ,因为1是最低元素,5是最高元素,4是中间元素,所有元素都是唯一值,或 set()
但代码说话,我到目前为止的功能是
def relative_order(a):
rel=[]
for i in a:
loc = 0
for v in a:
if i > v:
loc += 1
rel.append(loc)
return rel
它确实有效,但由于我将大型列表发送到此函数中,并且我必须将每个元素与每次迭代中的所有元素进行比较,因此需要大约5秒,其中包含10.000个元素的列表。
我的问题是如何提高所述功能的速度,也许更多Pythonic,我尝试了理解列表,但我的Python技能缺乏,我只想出了实现这个问题的必要方法。
答案 0 :(得分:11)
这可以写成这样的列表理解:
lst = [1, 5, 4]
s = sorted(lst)
[s.index(x) for x in lst]
=> [0, 2, 1]
这是另一个测试,使用@ frb的例子:
lst = [10, 2, 3, 9]
s = sorted(lst)
[s.index(x) for x in lst]
=> [3, 0, 1, 2]
答案 1 :(得分:11)
这是另一个应该更有效的保持.index
进入列表,因为它表明不会发生重复值,所以我们可以进行查找O(1)而不是线性...(并实际符合要求):
>>> a = [10, 2, 3, 9]
>>> indexed = {v: i for i, v in enumerate(sorted(a))}
>>> map(indexed.get, a)
[3, 0, 1, 2]
答案 2 :(得分:1)
你所拥有的方法需要n ^ 2次才能获得n ^ 2次的命令
。这应该在log(n)时间内起作用:
def relative_order(a): positions = sorted(range(len(a)), key=lambda i: a[i]) return sorted(range(len(a)), key = lambda i: positions[i])
它仍然是订单日志(n),因此也适用于您的大型列表。
编辑:
在lambda之外。
答案 3 :(得分:1)
def relative_order(a):
l = sorted(a)
# hash table of element -> index in ordered list
d = dict(zip(l, range(len(l))))
return [d[e] for e in a]
print relative_order([1, 5, 4])
print relative_order([2, 3, 1])
print relative_order([10, 2, 3, 9])
[0, 2, 1]
[1, 2, 0]
[3, 0, 1, 2]
该算法应该与sort类似,但使用额外的空间。
答案 4 :(得分:-1)
您的问题是关于排序。我建议使用Numpy或'Numeric Python'。 Numpy是一个Python模块,针对“快速,紧凑,多维数组设备”进行了优化。它是Python中科学计算的首选软件包。 http://www.numpy.org/
import numpy as np
input_array = np.array([1, 5, 4])
sorted_indices = np.argsort(input_array)
print sorted_indices
#[0 2, 1]
我还根据大小为50000
的数组添加了探查器输出。它表明这个方法比使用Python sorted
函数快了大约4倍(按照前面的答案)。
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.009 0.009 0.009 0.009 {method 'argsort' of 'numpy.ndarray' objects}
1 0.034 0.034 0.034 0.034 {sorted}
警告:强> 评论建议答案不符合作者的功能。这是真的。我想argsort的全部意义在于:
sorted_array = input_array[sorted_indices]
为您提供排序数组。
OP很奇怪,我想要一个结果,需要通过以下方式提供排序数组:
for i, val in enumerate(sorted_indices):
sorted_array[val] = input_array[i]