我有一个非常大的Python bitarray(大小超过1亿)。
我想知道一组True值的每次出现的偏移量和每组的大小(连续的'1'的数量)。例如:
在bitarray([“0001110000110”])中,第一次出现的一组True值在偏移3中,大小为3,第二次出现在偏移量10中,大小为2.
我试图遍历数组并手动计算它,但似乎不是一个安全的方法来循环一个非常大的比特阵列。我已经看过bitarray的文档,但是我无法从bitarray的功能中找到一种有效的方法。
因此,我想知道是否有任何有效的方法可以做到这一点。
答案 0 :(得分:1)
如果您正在寻找一种有效的方法,您可以在C中执行此操作。此函数执行此操作并返回元组数组(位置,长度)。
static PyObject *
bitarray_searchOnes(bitarrayobject *self)
{
idx_t p = 0;
idx_t s = 0;
PyObject *list = PyList_New(0);
while (p < self->nbits) {
if (GETBIT(self, p) == 1) {
s+=1;
}
else {
if (s != 0) {
PyList_Append(list, (PyTuple_Pack(2,PyLong_FromLongLong(p-s),PyLong_FromLongLong(s))));
s=0;
}
}
p++;
}
if (s != 0) {
PyList_Append(list, (PyTuple_Pack(2,PyLong_FromLongLong(p-s),PyLong_FromLongLong(s))));
s=0;
}
return list;
}
您可以将其添加到源中的_bitarray.c
,并在bitarray_methods
中进行定义。你将在python中拥有a.searchOne()
。
编辑:更简单的方法是迭代python中的位数组。
def searchOnes(bitarray)
s=0
ind=0
arr=[]
for i in bitarray:
if i:
s+=1
elif s:
arr.append((ind-s,s))
s=0
ind+=1
if(s):
arr.append((ind-s,s))
return arr
但是在对23,000,000位的一些基准测试之后,这种方法在我的intel i7机器上平均约为3.6 seconds
,而c实现仅花费1 second
。
编辑:这就是我做基准测试的方式:
from bitarray import bitarray
from timeit import timeit
from random import choice
def test_searchOnes():
ba=bitarray(''.join(choice('01') for _ in xrange(23000000)))
print timeit(lambda:searchOnes(ba),number=1) # the python version
print timeit(lambda:ba.searchOnes(),number=1) # the C version
结果将是:
3.37723302841 # the python version
0.754848003387 # the C version
答案 1 :(得分:0)
这是一个纯Python实现(适用于Python 2),也许效果更好?
import itertools
def frerich(a):
groups = ((k, sum(1 for _ in g)) for k, g in itertools.groupby(a))
offset = 0
for k, l in groups:
if k:
yield (offset, l)
offset += l
我们的想法是,不是单独迭代每个位,而是让itertools.groupby
和sum
为我们做(假设它们非常有效),然后只迭代连续元素组, yield
True
组的偏移量和长度。此外,该功能不会基于您甚至不需要内存中的列表的假设来构建列表。相反,它是一个发电机。