5

What's the fastest way to convert a list of booleans into a binary string in python?

e.g. boolList2BinString([True, True, False]) = '0b110'.

Also, how would I convert that binary string into the binary literal? Would this take more time than just converting from the boolean list to the binary literal immediatley? How would one do this?

e.g. boolList2Bin([True, True, False]) = 0b110.

Thanks!

geofflittle
  • 437
  • 1
  • 3
  • 14
  • An extension module written in C -- pre-allocating the space for the string and doing reference comparisons with `Py_True` -- is probably fastest. /s Seriously though, how serious is the "fastest" requirement? Did you add that just because or have you tried something and it was too slow (if so, please add details!). –  Feb 27 '14 at 00:23

5 Answers5

10

Regarding your first question, you can use a list comprehension* and a conditional expression:

>>> def boolList2BinString(lst):
...     return '0b' + ''.join(['1' if x else '0' for x in lst])
...
>>> boolList2BinString([True, True, False])
'0b110'
>>>

Regarding your second, you cannot "convert that binary string into the binary literal". As their name suggests, literals must be literally typed out:

>>> x = 0b110
>>>

Perhaps you meant that you want the quotes removed from the output? If so, use print:

>>> def boolList2BinString(lst):
...     return '0b' + ''.join(['1' if x else '0' for x in lst])
...
>>> boolList2BinString([True, True, False])
'0b110'
>>> print(boolList2BinString([True, True, False]))
0b110
>>>

*Note: I purposefully chose to use a list comprehension with str.join instead of a generator expression because the former is generally faster.

Community
  • 1
  • 1
  • Remove the brackets. `join` can handle generators, so you do not need to create a `list` first. – Alfe Feb 27 '14 at 00:38
  • Instead of the `if`/`else` you can use `'01'[x]` because bools can be used as indexes. – Alfe Feb 27 '14 at 00:39
  • this is the most efficient solution there is(at least out of the posted solutions) by a good margin +1 – Joran Beasley Feb 27 '14 at 00:41
  • 2
    @Alfe - You are correct that you do not _need_ a list with `str.join`. But the link I gave in my answer shows that it is generally faster to use one. Also, if you use [`timeit.timeit`](http://docs.python.org/3/library/timeit.html#timeit.timeit), you will see that the conditional expression is slightly faster than `'01'[x]`. –  Feb 27 '14 at 00:44
  • Whoa. My bad :( I ignored the __Note__ below the answer, sorry. And now that I want to revoke my downvote I only can so if the answer has changed. May I humbly ask you for doing a minor edit of it just for allowing me to? – Alfe Feb 27 '14 at 00:51
  • Much obliged, and again my apologies for being so hasty :-/ – Alfe Feb 27 '14 at 01:06
6

Convert the list to a decent binary (will be a long int):

number = reduce(lambda a, b: (a<<1) + int(b), [ True, True, False ])

And then, if you really need a "binary string", as you put it, use

bin(number)

to generate that string.

EDIT

You also can use this code:

number = sum(int(bit) << position
             for (position, bit) in
             enumerate(reversed([True, True, False])))

The mechanism behind it is the same as before.

Alfe
  • 56,346
  • 20
  • 107
  • 159
  • 2
    In Python 3+ `reduce` us moved to [`functools`](https://docs.python.org/3.5/library/functools.html#functools.reduce) module. – OrangeTux Oct 20 '15 at 10:01
4
data = [True, True, False]
print bin(int("".join(str(int(item)) for item in data), 2))
# 0b110
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
2
values = [True,False,False,True]
bin(sum(int(v)*2**i for i,v in enumerate(values[::-1]) ))

actually

In [7]: %timeit bin(sum(int(v)*2**i for i,v in enumerate(values[::-1]) ))
10000 loops, best of 3: 108 us per loop

In [8]: %timeit '0b' + ''.join(['1' if x else '0' for x in values])
100000 loops, best of 3: 5.25 us per loop

In [9]: %timeit bin(int("".join(str(int(item)) for item in values), 2))
10000 loops, best of 3: 29.5 us per loop

In [10]: %timeit bin(reduce(lambda a, b: (a<<1) + int(b), values))
10000 loops, best of 3: 31.3 us per loop

my solution is the slowest :( ...

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
0
L = [True, False, True]
''.join(map(str, map(int, L))) # '101'. 
Hunaphu
  • 589
  • 10
  • 11
  • Just timed it, this solution is three times slower than the accepted one. While the difference might often not matter, the question was specifically about the fastest way to do this, so here it does matter. – joanis Sep 30 '21 at 13:26