在非常大的Python比特率中了解一组True值的大小的最佳方法

时间:2016-01-20 04:25:42

标签: python loops bitarray

我有一个非常大的Python bitarray(大小超过1亿)。

我想知道一组True值的每次出现的偏移量和每组的大小(连续的'1'的数量)。例如:

在bitarray([“0001110000110”])中,第一次出现的一组True值在偏移3中,大小为3,第二次出现在偏移量10中,大小为2.

我试图遍历数组并手动计算它,但似乎不是一个安全的方法来循环一个非常大的比特阵列。我已经看过bitarray的文档,但是我无法从bitarray的功能中找到一种有效的方法。

因此,我想知道是否有任何有效的方法可以做到这一点。

2 个答案:

答案 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.groupbysum为我们做(假设它们非常有效),然后只迭代连续元素组, yield True组的偏移量和长度。此外,该功能不会基于您甚至不需要内存中的列表的假设来构建列表。相反,它是一个发电机。