如何按范围对列表元素进行分组/计数

pyI*_*Sky 4 python dictionary list

如果我的x列表和y列表是:

x = [10,20,30]
y = [1,2,3,15,22,27]
Run Code Online (Sandbox Code Playgroud)

我希望返回值是一个字典,其中包含的元素数小于x值:

{
    10:3,
    20:1,
    30:2,
}
Run Code Online (Sandbox Code Playgroud)

我有一个非常大的列表,所以我希望有一个更好的方法来做这个不涉及缓慢的嵌套for循环.我看过集合.Counter和itertools似乎都没有提供分组方式.有没有可以做到这一点的内置?

Ash*_*ary 8

您可以使用该bisect模块和collections.Counter:

>>> import bisect
>>> from collections import Counter
>>> Counter(x[bisect.bisect_left(x, item)] for item in y)
Counter({10: 3, 30: 2, 20: 1})
Run Code Online (Sandbox Code Playgroud)


ask*_*han 5

如果您愿意使用numpy,则基本上是在要求直方图:

x = [10,20,30]
y = [1,2,3,15,22,27]

np.histogram(y,bins=[0]+x)
#(array([3, 1, 2]), array([ 0, 10, 20, 30]))
Run Code Online (Sandbox Code Playgroud)

为了使这个命令:

b = np.histogram(y,bins=[0]+x)[0]
d = { k:v for k,v in zip(x, b)}
Run Code Online (Sandbox Code Playgroud)

对于短列表,这是不值得的,但是如果您的列表很长,则可能是:

In [292]: y = np.random.randint(0, 30, 1000)

In [293]: %%timeit
   .....: b = np.histogram(y, bins=[0]+x)[0]
   .....: d = { k:v for k,v in zip(x, b)}
   .....: 
1000 loops, best of 3: 185 µs per loop

In [294]: y = list(y)

In [295]: timeit Counter(x[bisect.bisect_left(x, item)] for item in y)
100 loops, best of 3: 3.84 ms per loop

In [311]: timeit dict(zip(x, [[n_y for n_y in y if n_y < n_x] for n_x in x]))
100 loops, best of 3: 3.75 ms per loop
Run Code Online (Sandbox Code Playgroud)