提供了一个列表
a=[3,7,4,2,0]
我想将列表中的每个元素与列表中的所有元素进行比较
所以对于第一个数字3,我希望将其与3,7,4,2,0进行比较,如果3小于或等于元素将1添加到空白列表中
重复此步骤将给出列表
b=[3,1,2,4,5]
这意味着对于第一个数字3,列表a中有3个数字小于或等于a的元素
我尝试使用itertools.combination进行比较,但是并没有比较相同的声誉。
另一种方法是使用两个for循环并制作一个方矩阵进行比较,但这不起作用(花费很长时间才能获得结果)
答案 0 :(得分:1)
探讨了三种方法
代码
import bisect
def bisect_method(a):
b = sorted(a)
return [len(a) - bisect.bisect_left(b, x) for x in a]
def counter_method(arr):
# Count of values in array
cnts = {i:0 for i in range(max(arr)+1)}
for i in range(len(arr)):
cnts[arr[i]] += 1
# Store the sum of cnts of elements
# greater than the current eleement
cnt_ge = 0
for k, cnt in reversed(cnts.items()):
cnts[k] = cnt_ge + cnts[k]
cnt_ge = cnts[k]
# cnts[arr[k]] has count of greater or equal to
return [cnts[x] for x in arr]
# Improvement to counter_method
# initialize cnts using set of array values
# as suggested by tobias_k
def counter_set_method(arr):
# Count of values in array
cnts = {i:0 for i in set(arr)}
for i in range(len(arr)):
cnts[arr[i]] += 1
# Store the sum of cnts of elements
# greater than the current eleement
cnt_ge = 0
for k, cnt in reversed(cnts.items()):
cnts[k] = cnt_ge + cnts[k]
cnt_ge = cnts[k]
# cnts[arr[k]] has count of greater or equal to
return [cnts[x] for x in arr]
验证
未触发声明,因此结果相同
for a in [[3, 7, 4, 2, 0], [3, 7, 4, 2, 0, 4]]:
assert bisect_method(a) == counter_method(a) == counter_set_method(a)
from random import randint
a = [randint(0, 10**5) for _ in range(10**6)]
assert bisect_method(a) == counter_method(a) == counter_set_method(a)
注意:
性能
测试代码
from random import randint
import numpy as np
import benchit # https://pypi.org/project/benchit/
funcs = [counter_method, counter_set_method, bisect_method]
inputs = [[randint(0, 10**5) for _ in range(x)] for x in 10**np.arange(7)]
t = benchit.timings(funcs, inputs)
print(t)
t.plot(logy=True, logx=True)
基准
Functions counter_method counter_set_method bisect_method
Len
1 0.008725 0.000003 0.000001
10 0.035918 0.000008 0.000004
100 0.038195 0.000066 0.000051
1000 0.041830 0.000670 0.000717
10000 0.048070 0.007392 0.009392
100000 0.113914 0.096876 0.144737
1000000 0.708296 0.813105 2.653164
答案 1 :(得分:0)
不不比较所有元素对,它们将是O(n²)。相反,您可以对列表进行排序,然后使用bisect
模块对sorted
数组进行二进制搜索以找到正确的位置,以插入元素并从该位置获取较大元素的数量。复杂度是O(nlogn)。
>>> import bisect
>>> a = [3, 7, 4, 2, 0]
>>> b = sorted(a)
>>> [len(a) - bisect.bisect_left(b, x) for x in a]
[3, 1, 2, 4, 5]
({bisect_left(b, x)
就是在排序列表中插入元素的位置,即元素的数量比x
小;因为您需要元素x
小于或等于,则需要减去len(a)
。
这对于重复的元素也有效,并且产生与简单的O(n²)方法相同的结果:
>>> a = [3, 7, 4, 2, 0, 4]
>>> b = sorted(a)
>>> [len(a) - bisect.bisect_left(b, x) for x in a]
[4, 1, 3, 5, 6, 3]
>>> [sum(1 for y in a if x<=y) for x in a] # just for reference, do not use this
[4, 1, 3, 5, 6, 3]
答案 2 :(得分:0)
为避免多次比较,可以使用以下内容:
b = [sorted(a, reverse=True).index(i)+1 for i in a]