这是我想要的行为:
a: IGADKYFHARGNYDAA
c: KGADKYFHARGNYEAA
2 difference(s).
这是我想要的行为:
a: IGADKYFHARGNYDAA
c: KGADKYFHARGNYEAA
2 difference(s).
def diff_letters(a,b):
return sum ( a[i] != b[i] for i in range(len(a)) )
zip
:sum(1 for x,y in zip(a, b) if x != y)
。在我看来,对布尔值求和有点不太直观 :P - Niklas B.sum(x!=y for x,y in zip(a,b))
是一种更稳定的方法,因为给定的示例将在a
和b
长度不同时出错。 - Jack Aidleylist.count(True)
比 sum()
更快。 - young_souvlaki我认为这个例子将适用于您的具体情况,而且不会给您的Python软件版本带来太多麻烦,也不会出现互操作性问题(请升级到2.7):
a='IGADKYFHARGNYDAA'
b='KGADKYFHARGNYEAA'
u=zip(a,b)
d=dict(u)
x=[]
for i,j in d.items():
if i==j:
x.append('*')
else:
x.append(j)
print x
输出:['*', 'E', '*', '*', 'K', '*', '*', '*', '*', '*']
通过一些调整,你可以得到你想要的内容... 如果有帮助,请告诉我 :-)
更新
你也可以使用这个:
a='IGADKYFHARGNYDAA'
b='KGADKYFHARGNYEAA'
u=zip(a,b)
for i,j in u:
if i==j:
print i,'--',j
else:
print i,' ',j
输出:
I K
G -- G
A -- A
D -- D
K -- K
Y -- Y
F -- F
H -- H
A -- A
R -- R
G -- G
N -- N
Y -- Y
D E
A -- A
A -- A
更新2
你可以修改代码如下:
y=[]
counter=0
for i,j in u:
if i==j:
print i,'--',j
else:
y.append(j)
print i,' ',j
print '\n', y
print '\n Length = ',len(y)
输出:
I K
G -- G
A -- A
D -- D
K -- K
Y -- Y
F -- F
H -- H
A -- A
R -- R
G -- G
N -- N
Y -- Y
D E
A -- A
A X
['K', 'E', 'X']
Length = 3
|
字符将结果存储在一个新字符串中,对于每个不同的字符,增加从零开始的整数值。您可以使用内置的zip
函数或itertools.izip
同时迭代两个字符串,后者在处理大量输入时性能更好。如果字符串大小不同,则仅针对较短部分进行迭代。如果是这种情况,则可以用表示不匹配的字符填充剩余部分。
import itertools
def compare(string1, string2, no_match_c=' ', match_c='|'):
if len(string2) < len(string1):
string1, string2 = string2, string1
result = ''
n_diff = 0
for c1, c2 in itertools.izip(string1, string2):
if c1 == c2:
result += match_c
else:
result += no_match_c
n_diff += 1
delta = len(string2) - len(string1)
result += delta * no_match_c
n_diff += delta
return (result, n_diff)
以下是一个简单的测试,和您之前提供的示例有些不同。请注意,我使用了下划线表示不匹配的字符,以更好地展示结果字符串如何扩展到较长字符串的大小。
def main():
string1 = 'IGADKYFHARGNYDAA AWOOH'
string2 = 'KGADKYFHARGNYEAA W'
result, n_diff = compare(string1, string2, no_match_c='_')
print "%d difference(s)." % n_diff
print string1
print result
print string2
main()
输出:
niklas@saphire:~/Desktop$ python foo.py
6 difference(s).
IGADKYFHARGNYDAA AWOOH
_||||||||||||_|||_|___
KGADKYFHARGNYEAA W
Python拥有优秀的difflib
库,该库提供了所需的功能。
以下是文档中的示例用法:
import difflib # Works for python >= 2.1
>>> s = difflib.SequenceMatcher(lambda x: x == " ",
... "private Thread currentThread;",
... "private volatile Thread currentThread;")
>>> for block in s.get_matching_blocks():
... print "a[%d] and b[%d] match for %d elements" % block
a[0] and b[0] match for 8 elements
a[8] and b[17] match for 21 elements
a[29] and b[38] match for 0 elements
a = "IGADKYFHARGNYDAA"
b = "KGADKYFHARGNYEAAXXX"
match_pattern = zip(a, b) #give list of tuples (of letters at each index)
difference = sum (1 for e in zipped if e[0] != e[1]) #count tuples with non matching elements
difference = difference + abs(len(a) - len(b)) #in case the two string are of different lenght, we add the lenght difference
我还没有看到有人使用reduce
函数,所以我会包含一段我一直在使用的代码:
reduce(lambda x, y: x + 1 if y[0] != y[1] else x, zip(source, target), 0)
这将为您提供source
和target
中不同字符的数量。
使用difflib.ndiff,你可以用一行代码实现这个功能,而且还比较容易理解:
>>> import difflib
>>> a = 'IGADKYFHARGNYDAA'
>>> c = 'KGADKYFHARGNYEAA'
>>> sum([i[0] != ' ' for i in difflib.ndiff(a, c)]) / 2
2
(sum
之所以有效,是因为 True == 1
和 False == 0
)
下面的内容可以清楚地说明正在发生什么以及为什么需要 / 2
:
>>> [i for i in difflib.ndiff(a,c)]
['- I',
'+ K',
' G',
' A',
' D',
' K',
' Y',
' F',
' H',
' A',
' R',
' G',
' N',
' Y',
'- D',
'+ E',
' A',
' A']
我喜欢 Niklas R 的 答案,但它有一个问题(取决于你的期望)。使用以下两个测试用例来测试答案:
print compare('berry','peach')
print compare('berry','cherry')
(' | ', 4) # berry, peach
(' | ', 5) # berry, cherry
这种情况发生在字符串反向比正向更相似的时候。为了扩展 Niklas R 的答案,我们可以添加一个辅助函数,该函数返回正常(正向)差异和反转字符串的差异之间的最小差异:
def fuzzy_compare(string1, string2):
(fwd_result, fwd_diff) = compare(string1, string2)
(rev_result, rev_diff) = compare(string1[::-1], string2[::-1])
diff = min(fwd_diff, rev_diff)
return diff
print fuzzy_compare('berry','peach')
print fuzzy_compare('berry','cherry')
...然后我们得到
4 # berry, peach
2 # berry, cherry
就像我之前所说的那样,这只是在 Niklas R. 的答案基础上进行了扩展,而不是修改。
如果你只是想要一个简单的差异函数(考虑到上述的陷阱),可以使用以下代码:
def diff(a, b):
delta = do_diff(a, b)
delta_rev = do_diff(a[::-1], b[::-1])
return min(delta, delta_rev)
def do_diff(a,b):
delta = 0
i = 0
while i < len(a) and i < len(b):
delta += a[i] != b[i]
i += 1
delta += len(a[i:]) + len(b[i:])
return delta
测试用例:
print diff('berry','peach')
print diff('berry','cherry')
最后一个考虑因素是diff函数在处理长度不同的单词时的本身。有两个选择:
例如:
当仅考虑最短单词时,我们可以使用:
def do_diff_shortest(a,b):
delta, i = 0, 0
if len(a) > len(b):
a, b = b, a
for i in range(len(a)):
delta += a[i] != b[i]
return delta
...迭代的次数由最短单词决定,其余的被忽略。或者我们可以考虑不同的长度:
def do_diff_both(a, b):
delta, i = 0, 0
while i < len(a) and i < len(b):
delta += a[i] != b[i]
i += 1
delta += len(a[i:]) + len(b[i:])
return delta
print do_diff_shortest('apple','apples')
print do_diff_both('apple','apples')
将输出:
0 # Ignore extra characters belonging to longest word.
1 # Consider extra characters.
a = 'IGADKYFHARGNYDAA'
b = 'KGADKYFHARGNYEAA'
counter = 0
differences = 0
for i in a:
if i != b[counter]:
differences += 1
counter += 1
def compare(string1, string2, no_match_c=' ', match_c='|'):
if len(string2) < len(string1):
string1, string2 = string2, string1
result = ''
n_diff = 0
for c1, c2 in zip(string1, string2):
if c1 == c2:
result += match_c
else:
result += no_match_c
n_diff += 1
delta = len(string2) - len(string1)
result += delta * no_match_c
n_diff += delta
return (result, n_diff)
设置两个字符串进行比较并调用函数:
def main():
string1 = 'AAUAAA'
string2 = 'AAUCAA'
result, n_diff = compare(string1, string2, no_match_c='_')
print("%d difference(s)." % n_diff)
print(string1)
print(result)
print(string2)
main()
这将返回:
1 difference(s).
AAUAAA
|||_||
AAUCAA