如果我的x列表和y列表是:
x = [10,20,30]
y = [1,2,3,15,22,27]
我希望返回值是一个字典,其中包含的元素数小于x值:
{
10:3,
20:1,
30:2,
}
我有一个非常大的列表,所以我希望有一个更好的方法来做这个不涉及缓慢的嵌套for循环。我看过集合.Counter和itertools似乎都没有提供分组方式。是否有可以做到这一点的内置?
答案 0 :(得分: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})
答案 1 :(得分:4)
如果你愿意使用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]))
使这成为一个词典:
b = np.histogram(y,bins=[0]+x)[0]
d = { k:v for k,v in zip(x, b)}
对于简短列表,这不值得,但如果您的列表很长,则可能是:
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
答案 2 :(得分:1)
简答:
dict(zip(x, [[n_y for n_y in y if n_y < n_x] for n_x in x]))
答案很长
首先,我们需要迭代y来检查哪个成员少于某个成员。如果我们这样做10,我们得到这个:
>>> [n_y for n_y in y if n_y < 10]
[1, 2, 3]
然后我们需要让'10'变成一个变量,然后抛出x:
>>> [[n_y for n_y in y if n_y < n_x] for n_x in x]
[[1, 2, 3], [1, 2, 3, 15], [1, 2, 3, 15, 22, 27]]
最后,我们需要使用原始x添加此结果。这是拉链派上用场的时候:
>>> zip(x, [[n_y for n_y in y if n_y < n_x] for n_x in x])
[(10, [1, 2, 3]), (20, [1, 2, 3, 15]), (30, [1, 2, 3, 15, 22, 27])]
这是一个元组列表,所以我们应该在它上面输出dict来得到最终结果:
>>> dict(zip(x, [[n_y for n_y in y if n_y < n_x] for n_x in x]))
{10: [1, 2, 3], 20: [1, 2, 3, 15], 30: [1, 2, 3, 15, 22, 27]}
答案 3 :(得分:0)
如果x
中的值之间的步长始终为10
,我会这样做:
>>> y = [1,2,3,15,22,27]
>>> step = 10
>>> from collections import Counter
>>> Counter(n - n%step + step for n in y)
Counter({10: 3, 30: 2, 20: 1})