繁体   English   中英

在Python中将二进制列表(或数组)转换为整数的最快方法

[英]Fastest way to convert a binary list(or array) into an integer in Python

假设有一个包含1和0的列表(或数组)。

gona = [1, 0, 0, 0, 1, 1]

我想将其转换为由二进制值100011 (由列表中的元素组成的数字)表示的整数。

我知道可以做到以下几点。

int("".join(map(str, gona)),2)

要么

编辑: int("".join([str(i) for i in gona]),2)

还有其他更快的方法吗?

这是我最快想到的。 您的初始解决方案略有不同:

digits = ['0', '1']
int("".join([ digits[y] for y in x ]), 2)

%timeit int("".join([digits[y] for y in x]),2)
100000 loops, best of 3: 6.15 us per loop
%timeit int("".join(map(str, x)),2)
100000 loops, best of 3: 7.49 us per loop

(顺便说一句,在这种情况下,使用列表理解似乎比使用生成器表达式更快。)

编辑:

另外,我讨厌成为一个聪明人,但是您总是可以以内存换取速度:

# one time precalculation
cache_N = 16  # or much bigger?!
cache = {
   tuple(x): int("".join([digits[y] for y in x]),2)
   for x in itertools.product((0,1), repeat=cache_N)
}

然后:

res = cache[tuple(x)]

更快。 当然,这仅在某种程度上是可行的...

编辑2:

现在,我看到您说您的列表包含32个元素。 在这种情况下,缓存解决方案可能是不可行的,但是我们有更多的方法来交换内存速度。 例如,使用cache_N=16 ,这肯定是可行的,您可以访问两次:

c = 2 ** cache_N # compute once
xx = tuple(x)
cache[xx[:16]] * c + cache[xx[16:]]

%timeit cache[xx[:16]] * c + cache[xx[16:]]
1000000 loops, best of 3: 1.23 us per loop  # YES!

您可以这样做:

sum(x << i for i, x in enumerate(reversed(gona)))

虽然不快

我决定创建一个脚本来试用4种执行此任务的方法。

import time

trials = range(1000000)
list1 = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0]
list0 = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
listmix = [1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0]

def test1(l):
    start = time.time()
    for trial in trials:
        tot = 0
        n = 1
    for i in reversed(l):
            if i:
                tot += 2**n
            n += 1
    print 'Time taken:', str(time.time() - start)

def test2(l):
    start = time.time()
    for trial in trials:
        int("".join(map(str, l)),2)
    print 'Time taken:', str(time.time() - start)

def test3(l):
    start = time.time()
    for trial in trials:
        sum(x << i for i, x in enumerate(reversed(l)))
    print 'Time taken:', str(time.time() - start)

def test4(l):
    start = time.time()
    for trial in trials:
        int("".join([str(i) for i in l]),2)
    print 'Time taken:', str(time.time() - start)


test1(list1)
test2(list1)
test3(list1)
test4(list1)
print '.'
test1(list0)
test2(list0)
test3(list0)
test4(list0)
print '.'
test1(listmix)
test2(listmix)
test3(listmix)
test4(listmix)

我的结果:

Time taken: 7.14670491219
Time taken: 5.4076821804
Time taken: 4.7349550724
Time taken: 7.24234819412
.
Time taken: 2.29213285446
Time taken: 5.38784003258
Time taken: 4.70707392693
Time taken: 7.27936697006
.
Time taken: 4.78960323334
Time taken: 5.36612486839
Time taken: 4.70103287697
Time taken: 7.22436404228

结论:@goncalopp的解决方案可能是最好的解决方案。 它一直都很快。 另一方面,如果您的零可能比零多,那么遍历列表并手动乘以2的幂并加起来将是最快的。

编辑:我重新编写了脚本以使用timeit,源代码位于http://pastebin.com/m6sSmmR6

我的输出结果:

7.78366303444
2.79321694374
5.29976511002
.
5.72017598152
5.70349907875
5.66881299019
.
5.25683712959
5.17318511009
5.20052909851
.
8.23388290405
8.24193501472
8.15649604797
.
3.94102287292
3.95323395729
3.9201271534

如果全为零,我逐步遍历列表的方法会向后加2的幂,但是,否则,@ sxh2的方法肯定是最快的,而且我的实现甚至不包括他的缓存优化。

我尝试了这个:

int(str(gona).replace(', ','')[1:-1])

并与此相比(最快的情况是@ Sohcahtoa82):

sum(x << i for i, x in enumerate(reversed(gona)))

在我的机器上,第一个完成的时间为1000000次,传输时间约为5.97秒。 第二种情况需要约8.03s。

我尝试了另一种方法,并将其插入@ Sohcahtoa82的代码中:

T61 = """
    l = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
    digits = ['0', '1']
    s = ''
    for y in l:
        s += digits[y]
    int(s, 2)
"""

T60 = """
    l = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
    digits = ['0', '1']
    s = ''
    for y in l:
        s += digits[y]
    int(s, 2)
"""

T6mix = """
    l = [1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0]
    digits = ['0', '1']
    s = ''
    for y in l:
        s += digits[y]
    int(s, 2)
"""

并得到了这些结果。 我的是最后一组时间。

5.45334255339
1.89000112578
4.14859673729
.
4.39018410496
4.21122597336
4.57919181895
.
3.59095765307
3.25353409619
3.78588067833
.
6.53343932548
6.33234985363
6.65685678006
.
2.74509861151
2.6111819044
2.83928911064
.
2.79519545737
2.66091503704
2.9183024407

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM