Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 获取字符串中不同索引数所需的快速方法_Python_C++_String_Optimization - Fatal编程技术网

Python 获取字符串中不同索引数所需的快速方法

Python 获取字符串中不同索引数所需的快速方法,python,c++,string,optimization,Python,C++,String,Optimization,我想得到两个不同字符串中的索引数 固定的事物: 字符串数据在任何索引上只有0或1。i、 字符串是数字的二进制表示形式 两个字符串的长度相同 对于上面的问题,我用python编写了下面的函数 def foo(a,b): result = 0 for x,y in zip(a,b): if x != y: result += 1 return result 但问题是这些弦是巨大的。非常大。因此,上述功能占用了太多的时间。我应该做些什么

我想得到两个不同字符串中的索引数

固定的事物:

字符串数据在任何索引上只有0或1。i、 字符串是数字的二进制表示形式

两个字符串的长度相同

对于上面的问题,我用python编写了下面的函数

def foo(a,b):
    result = 0
    for x,y in zip(a,b):
        if x != y:
            result += 1
    return result
但问题是这些弦是巨大的。非常大。因此,上述功能占用了太多的时间。我应该做些什么来让它超快

这是我在C++中做的,现在速度相当快,但是仍然不能理解如何用短整数和“yydououth:y/p>”所说的填充。

size_t diff(long long int n1, long long int n2)
{
long long int c = n1 ^ n2;
bitset<sizeof(int) * CHAR_BIT> bits(c);
string s = bits.to_string();

return std::count(s.begin(), s.end(), '1');

}
大小差异(长整型n1,长整型n2)
{
长整型c=n1^n2;
位集位(c);
字符串s=位。到_字符串();
返回std::count(s.begin(),s.end(),'1');
}

未测试,但其性能如何:

sum(x!=y for x,y in zip(a,b))

未测试,但其性能如何:

sum(x!=y for x,y in zip(a,b))

未测试,但其性能如何:

sum(x!=y for x,y in zip(a,b))

未测试,但其性能如何:

sum(x!=y for x,y in zip(a,b))

我将在这里介绍这些选项,但基本上你是在计算两个数字之间的汉明距离。有专门的库可以使这一过程非常非常快,但是让我们首先关注纯Python选项

你的方法,快
zip()
首先生成一个大列表,然后让您循环。您可以改用
itertools.izip()
,并使其成为生成器表达式:

from itertools import izip

def foo(a, b):
    return sum(x != y for x, y in izip(a, b))
这样一次只生成一对,避免了必须先创建一个大的元组列表

Python布尔类型是
int
的一个子类,其中
True==1
False==0
,可以对它们求和:

>>> True + True
2
改为使用整数 但是,您可能需要重新考虑输入数据。使用整数表示二进制数据更有效;整数可以直接运算。内联执行转换,然后计算异或结果上的1数为:

def foo(a, b):
    return format(int(a, 2) ^ int(b, 2), 'b').count('1')
但是,不必首先将
a
b
转换为整数将更加有效

时间比较:

>>> from itertools import izip
>>> import timeit
>>> s1 = "0100010010"
>>> s2 = "0011100010"
>>> def foo_zipped(a, b): return sum(x != y for x, y in izip(a, b))
... 
>>> def foo_xor(a, b): return format(int(a, 2) ^ int(b, 2), 'b').count('1')
... 
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_zipped as f')
1.7872788906097412
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor as f')
1.3399651050567627
>>> s1 = s1 * 1000
>>> s2 = s2 * 1000
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_zipped as f', number=1000)
1.0649528503417969
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor as f', number=1000)
0.0779869556427002
>>> def foo_gmpy_hamdist(a, b):
...     return gmpy.hamdist(int(a, 2), int(b, 2))
... 
>>> def foo_gmpy_hamdist_int(a, b):
...     return gmpy.hamdist(a, b)
... 
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor as f', number=100000)
7.479684114456177
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_gmpy_hamdist as f', number=100000)
4.340585947036743
>>> timeit.timeit('f(si1, si2)', 'from __main__ import si1, si2, foo_gmpy_hamdist_int as f', number=100000)
0.22896099090576172
如果输入变大,XOR方法的速度会加快几个数量级,这是首先将输入转换为
int

位计数专用库 位计数(
format(integer,'b').count(1)
)非常快,但如果您安装了(围绕的Python包装器)并使用
gmpy.popcount()函数,则可以使其更快:

def foo(a, b):
    return gmpy.popcount(int(a, 2) ^ int(b, 2))
gmpy.popcount()
在我的机器上比
str.count()方法快20倍左右。同样,不必首先将
a
b
转换为整数将消除另一个瓶颈,但即使如此,每次呼叫的性能也几乎翻了一番:

>>> import gmpy
>>> def foo_xor_gmpy(a, b): return gmpy.popcount(int(a, 2) ^ int(b, 2))
... 
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor as f', number=10000)
0.7225301265716553
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor_gmpy as f', number=10000)
0.47731995582580566
为了说明
a
b
是以整数开头时的区别:

>>> si1, si2 = int(s1, 2), int(s2, 2)
>>> def foo_xor_int(a, b): return format(a ^ b, 'b').count('1')
... 
>>> def foo_xor_gmpy_int(a, b): return gmpy.popcount(a ^ b)
... 
>>> timeit.timeit('f(si1, si2)', 'from __main__ import si1, si2, foo_xor_int as f', number=100000)
3.0529568195343018
>>> timeit.timeit('f(si1, si2)', 'from __main__ import si1, si2, foo_xor_gmpy_int as f', number=100000)
0.15820622444152832
def foo_gmpy_hamdist_int(a, b):
    return gmpy.hamdist(a, b)
汉明距离专用库
gmpy
库实际上包含一个
gmpy.hamdist()
函数,它直接计算这个精确数字(整数的异或结果中的1位数):

如果你用整数开头,这会让你大吃一惊:

>>> si1, si2 = int(s1, 2), int(s2, 2)
>>> def foo_xor_int(a, b): return format(a ^ b, 'b').count('1')
... 
>>> def foo_xor_gmpy_int(a, b): return gmpy.popcount(a ^ b)
... 
>>> timeit.timeit('f(si1, si2)', 'from __main__ import si1, si2, foo_xor_int as f', number=100000)
3.0529568195343018
>>> timeit.timeit('f(si1, si2)', 'from __main__ import si1, si2, foo_xor_gmpy_int as f', number=100000)
0.15820622444152832
def foo_gmpy_hamdist_int(a, b):
    return gmpy.hamdist(a, b)
比较:

>>> from itertools import izip
>>> import timeit
>>> s1 = "0100010010"
>>> s2 = "0011100010"
>>> def foo_zipped(a, b): return sum(x != y for x, y in izip(a, b))
... 
>>> def foo_xor(a, b): return format(int(a, 2) ^ int(b, 2), 'b').count('1')
... 
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_zipped as f')
1.7872788906097412
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor as f')
1.3399651050567627
>>> s1 = s1 * 1000
>>> s2 = s2 * 1000
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_zipped as f', number=1000)
1.0649528503417969
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor as f', number=1000)
0.0779869556427002
>>> def foo_gmpy_hamdist(a, b):
...     return gmpy.hamdist(int(a, 2), int(b, 2))
... 
>>> def foo_gmpy_hamdist_int(a, b):
...     return gmpy.hamdist(a, b)
... 
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor as f', number=100000)
7.479684114456177
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_gmpy_hamdist as f', number=100000)
4.340585947036743
>>> timeit.timeit('f(si1, si2)', 'from __main__ import si1, si2, foo_gmpy_hamdist_int as f', number=100000)
0.22896099090576172
这是两个3k+数字之间的汉明距离的100.000倍

另一个可以计算距离的包是,它支持直接计算字符串之间的汉明距离

确保使用
--with-c
开关编译c优化;使用
pip
安装时,请使用
bin/pip安装距离--安装选项--例如使用-c

再次使用位计数方法对XOR进行基准测试:

>>> import distance
>>> def foo_distance_hamming(a, b):
...     return distance.hamming(a, b)
... 
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor as f', number=100000)
7.229060173034668
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_distance_hamming as f', number=100000)
0.7701470851898193

它使用天真的方法;压缩两个输入字符串并计算差异的数量,但由于它在C中这样做,所以速度仍然快得多,大约是C的10倍。当你使用整数时,
gmpy.hamdist()
函数仍然优于它。

我将在这里介绍这些选项,但基本上你是在计算两个数字之间的汉明距离。有专门的库可以使这一过程非常非常快,但是让我们首先关注纯Python选项

你的方法,快
zip()
首先生成一个大列表,然后让您循环。您可以改用
itertools.izip()
,并使其成为生成器表达式:

from itertools import izip

def foo(a, b):
    return sum(x != y for x, y in izip(a, b))
这样一次只生成一对,避免了必须先创建一个大的元组列表

Python布尔类型是
int
的一个子类,其中
True==1
False==0
,可以对它们求和:

>>> True + True
2
改为使用整数 但是,您可能需要重新考虑输入数据。使用整数表示二进制数据更有效;整数可以直接运算。内联执行转换,然后计算异或结果上的1数为:

def foo(a, b):
    return format(int(a, 2) ^ int(b, 2), 'b').count('1')
但是,不必首先将
a
b
转换为整数将更加有效

时间比较:

>>> from itertools import izip
>>> import timeit
>>> s1 = "0100010010"
>>> s2 = "0011100010"
>>> def foo_zipped(a, b): return sum(x != y for x, y in izip(a, b))
... 
>>> def foo_xor(a, b): return format(int(a, 2) ^ int(b, 2), 'b').count('1')
... 
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_zipped as f')
1.7872788906097412
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor as f')
1.3399651050567627
>>> s1 = s1 * 1000
>>> s2 = s2 * 1000
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_zipped as f', number=1000)
1.0649528503417969
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor as f', number=1000)
0.0779869556427002
>>> def foo_gmpy_hamdist(a, b):
...     return gmpy.hamdist(int(a, 2), int(b, 2))
... 
>>> def foo_gmpy_hamdist_int(a, b):
...     return gmpy.hamdist(a, b)
... 
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor as f', number=100000)
7.479684114456177
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_gmpy_hamdist as f', number=100000)
4.340585947036743
>>> timeit.timeit('f(si1, si2)', 'from __main__ import si1, si2, foo_gmpy_hamdist_int as f', number=100000)
0.22896099090576172
如果输入变大,XOR方法的速度会加快几个数量级,这是首先将输入转换为
int

位计数专用库 位计数(
format(integer,'b').count(1)
)非常快,但如果您安装了(围绕的Python包装器)并使用
gmpy.popcount()函数,则可以使其更快:

def foo(a, b):
    return gmpy.popcount(int(a, 2) ^ int(b, 2))
gmpy.popcount()
在我的机器上比
str.count()方法快20倍左右。同样,不必首先将
a
b
转换为整数将消除另一个瓶颈,但即使如此,每次呼叫的性能也几乎翻了一番:

>>> import gmpy
>>> def foo_xor_gmpy(a, b): return gmpy.popcount(int(a, 2) ^ int(b, 2))
... 
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor as f', number=10000)
0.7225301265716553
>>> timeit.timeit('f(s1, s2)', 'from __main__ import s1, s2, foo_xor_gmpy as f', number=10000)
0.47731995582580566
说明
a
b
为int时的区别