[英]comparing a value of a list with other values in the same list with reputation
给出一个列表
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 循环并制作一个方阵进行比较,但这不起作用(需要很长时间才能得到结果)
探索了三种方法
代码
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
不要比较所有元素对,这将是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]
为避免多重比较,您可以使用以下方法:
b = [sorted(a, reverse=True).index(i)+1 for i in a]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.