Разделите буквы разницей двух строк

Это поведение, которое я хочу:

a: IGADKYFHARGNYDAA
c: KGADKYFHARGNYEAA
2 difference(s).

Ответ 1

Я предполагаю, что этот 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

Ответ 2

def diff_letters(a,b):
    return sum ( a[i] != b[i] for i in range(len(a)) )

Ответ 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()

Вывод:

[email protected]:~/Desktop$ python foo.py 
6 difference(s).
IGADKYFHARGNYDAA AWOOH
_||||||||||||_|||_|___
KGADKYFHARGNYEAA  W

Ответ 4

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    

Ответ 5

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

Ответ 6

С 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']

Это также хорошо работает, если строки имеют разную длину.

Ответ 7

При переходе по одной строке создайте объект-счетчик, который идентифицирует букву, на которой вы находитесь, на каждой итерации. Затем используйте этот счетчик в качестве индекса для ссылки на другую последовательность.

a = 'IGADKYFHARGNYDAA'
b = 'KGADKYFHARGNYEAA'

counter = 0
differences = 0
for i in a:
    if i != b[counter]:
        differences += 1
    counter += 1

Здесь каждый раз, когда мы сталкиваемся с буквой в последовательности а, которая отличается от буквы в том же положении в последовательности b, мы добавляем 1 к "различиям". Затем мы добавляем 1 к счетчику, прежде чем переместимся на следующую букву.

Ответ 8

Мне нравится ответ от 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 при обработке слов различной длины. Существует два варианта:

  • Рассмотрим разницу между длинами как отличительными символами.
  • Игнорировать разницу в длине и сравнивать только кратчайшее слово.

Например:

  • яблоко и яблоки имеют разницу в 1 при рассмотрении всех персонажи.
  • яблоко и яблоки имеют разность 0, когда учитывая только кратчайшее слово

Рассматривая только кратчайшее слово, которое мы можем использовать:

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.

Ответ 9

Вот мое решение аналогичной проблемы, сравнивая две строки на основе представленного здесь решения: 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