Если вам нужна максимальная эффективность, один пакет, который должен приблизить вас, - bitarray
.Он написан на c, поэтому молниеносно.
Чтобы создать bitarray
, вы можете передать конструктору bitarray
любую последовательность логических значений.Например:
>>> bitarray.bitarray([1, 1, 0, 1])
bitarray('1101')
>>> bitarray.bitarray([True, True, False, True])
bitarray('1101')
>>> bitarray.bitarray([range(3), [5.829048], [], ['can', 'I', 'help', 'you?']])
bitarray('1101')
Я сделал несколько таймингов, и действительно bitarray
самый быстрый для более длинных строк.Но было несколько неожиданностей:
bitarray
только на 50% быстрее, чем int(''.join(bs))
в большинстве случаев. int(''.join(bs))
быстрее, чем предложенный метод shift
на tomasz для длин a
больше 3000 и в порядке быстрее для длин a
больше 30000. - даже для маленьких
len(a)
,использование метода shift
происходит всего в несколько раз быстрее.Асимптотическое повышение производительности, которое ''.join()
обеспечивает для более длинных строк, составляет порядка секунд или десятков секунд, в то время как метод shift
обеспечивает усиление только порядка миллисекунд для небольших строк.Таким образом, использование ''.join()
здесь является явным победителем.
Так что, если вы не хотите использовать стороннюю библиотеку, то использование ''.join()
, как вы делали выше, является лучшим решением!И действительно, польза от использования сторонней библиотеки в этом случае минимальна;так что, в конце концов, я бы не советовал, в конце концов - если вы в основном не хотите экономить память.
Наконец , одно небольшое замечание: вам не нужно добавлять '0b'
к строке, как вы делали выше.Просто позвоните int(bitstring, 2)
- базовый аргумент (2
) делает '0b'
избыточным.
>>> import array
>>> import random
>>> import bitarray
>>>
>>> #### Definitions: ####
>>>
>>> def a_mask_join(a):
..... d = dict()
..... for i in set(a):
..... d[i] = int(''.join([str(int(i is b)) for b in a]), 2)
..... return d
.....
>>> def mask(values, x):
..... m = 0
..... for v in values:
..... m = (m << 1) + (v == x)
..... return m
.....
>>> def a_mask_shift(a):
..... d = dict()
..... for i in set(a):
..... d[i] = mask(a, i)
..... return d
.....
>>> def a_mask_bitarray1(a):
..... d = dict()
..... for i in set(a):
..... d[i] = bitarray.bitarray([int(i is b) for b in a])
..... return d
.....
>>> def a_mask_bitarray2(a):
..... d = dict()
..... for i in set(a):
..... d[i] = int(bitarray.bitarray([int(i is b) for b in a]).to01(), 2)
..... return d
.....
>>> a = array.array('B', [4,5,13,4,4,9,12,13])
>>>
>>> #### Test: ####
>>>
>>> dicts = (f(a) for f in (a_mask_join, a_mask_shift1, a_mask_shift2, a_mask_bitarray2))
>>> sorted_results = (sorted(int(v) for v in d.values()) for d in dicts)
>>> all(r == sorted(a_mask1(a).values()) for r in sorted_results)
True
>>>
>>> #### Timing: ####
>>>
>>> for size in (int(10 ** (e / 2.0)) for e in range(2, 11)):
..... print size
..... a = array.array('B', [random.randrange(0, 30) for _ in range(size)])
..... %timeit a_mask_join(a)
..... %timeit a_mask_shift(a)
..... %timeit a_mask_bitarray1(a)
..... %timeit a_mask_bitarray2(a)
.....
10
10000 loops, best of 3: 61.2 us per loop
100000 loops, best of 3: 17.5 us per loop
10000 loops, best of 3: 38.4 us per loop
10000 loops, best of 3: 46.7 us per loop
31
1000 loops, best of 3: 343 us per loop
10000 loops, best of 3: 97.9 us per loop
1000 loops, best of 3: 212 us per loop
1000 loops, best of 3: 242 us per loop
100
1000 loops, best of 3: 1.45 ms per loop
1000 loops, best of 3: 486 us per loop
1000 loops, best of 3: 825 us per loop
1000 loops, best of 3: 870 us per loop
316
100 loops, best of 3: 4.53 ms per loop
100 loops, best of 3: 2.46 ms per loop
100 loops, best of 3: 2.53 ms per loop
100 loops, best of 3: 2.65 ms per loop
1000
100 loops, best of 3: 14.5 ms per loop
100 loops, best of 3: 10.8 ms per loop
100 loops, best of 3: 7.78 ms per loop
100 loops, best of 3: 8.04 ms per loop
3162
10 loops, best of 3: 47.4 ms per loop
10 loops, best of 3: 71.8 ms per loop
10 loops, best of 3: 24.1 ms per loop
10 loops, best of 3: 25.6 ms per loop
10000
10 loops, best of 3: 137 ms per loop
1 loops, best of 3: 425 ms per loop
10 loops, best of 3: 75.7 ms per loop
10 loops, best of 3: 78 ms per loop
31622
1 loops, best of 3: 430 ms per loop
1 loops, best of 3: 3.25 s per loop
1 loops, best of 3: 241 ms per loop
1 loops, best of 3: 246 ms per loop
100000
1 loops, best of 3: 1.37 s per loop
1 loops, best of 3: 29.7 s per loop
1 loops, best of 3: 805 ms per loop
1 loops, best of 3: 800 ms per loop