Это поведение, которое я хочу:
a: IGADKYFHARGNYDAA
c: KGADKYFHARGNYEAA
2 difference(s).
Это поведение, которое я хочу:
a: IGADKYFHARGNYDAA
c: KGADKYFHARGNYEAA
2 difference(s).
Я предполагаю, что этот exmaple будет работать для вас в этом конкретном случае без особых сложностей и проблем с совместимостью с вашей версией программного обеспечения на 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', '*', '*', '*', '*', '*']
С небольшим количеством touakings вы можете получить то, что хотите.... Скажите, если это поможет: -)
Обновление
Вы также можете использовать это:
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
def diff_letters(a,b):
return sum ( a[i] != b[i] for i in range(len(a)) )
|
, соответственно. Также увеличьте целочисленное значение, начиная с нуля для каждого другого символа.Вы можете использовать встроенную функцию 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()
Вывод:
[email protected]:~/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
С 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']
Это также хорошо работает, если строки имеют разную длину.
При переходе по одной строке создайте объект-счетчик, который идентифицирует букву, на которой вы находитесь, на каждой итерации. Затем используйте этот счетчик в качестве индекса для ссылки на другую последовательность.
a = 'IGADKYFHARGNYDAA'
b = 'KGADKYFHARGNYEAA'
counter = 0
differences = 0
for i in a:
if i != b[counter]:
differences += 1
counter += 1
Здесь каждый раз, когда мы сталкиваемся с буквой в последовательности а, которая отличается от буквы в том же положении в последовательности b, мы добавляем 1 к "различиям". Затем мы добавляем 1 к счетчику, прежде чем переместимся на следующую букву.
Мне нравится ответ от Niklas R, но у него есть проблема (в зависимости от ваших ожиданий). Используя ответ со следующими двумя тестовыми примерами:
print compare('berry','peach')
print compare('berry','cherry')
Мы можем разумно ожидать, что вишня будет больше похожа на ягода, чем на персик. Тем не менее мы получаем более низкий уровень между ягодный и персик, затем ягода и вишня:
(' | ', 4) # berry, peach
(' | ', 5) # berry, cherry
Это происходит, когда строки больше похожи назад, чем вперед. Чтобы продлить ответ от ответа от Niklas R, мы можем добавить вспомогательную функцию, которая возвращает минимальный разность между нормальным (вперед) diff и разностью обратных строк:
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.
Если вы просто ищете простую функцию diff (с учетом вышеупомянутой gotcha), выполните следующие действия:
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
В этом примере все остальные символы подсчитываются и добавляются к значению diff. Чтобы проверить обе функции
print do_diff_shortest('apple','apples')
print do_diff_both('apple','apples')
Будет выводиться:
0 # Ignore extra characters belonging to longest word.
1 # Consider extra characters.
Вот мое решение аналогичной проблемы, сравнивая две строки на основе представленного здесь решения: fooobar.com/info/482398/....
Так как itertools.izip не работал у меня в Python3, я нашел решение, которое вместо этого просто использует zip-функцию: fooobar.com/info/482399/....
Функция сравнения двух строк:
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