# Counting length-2 substrings that are common to two strings at the same offset -- Python

Given 2 strings, a and b, return the number of the positions where they contain the same length 2 substring. So "xxcaazz" and "xxbaaz" yields 3, since the "xx", "aa", and "az" substrings appear in the same place in both strings.

stringMatch("xxcaazz", "xxbaaz") → 3
stringMatch("abc", "abc") → 2
stringMatch("abc", "axc") → 0

import doctest

def all_two_chars_occurencies(string):
"""
>>> list(all_two_chars_occurencies('abcd'))
['ab', 'bc', 'cd']
>>> list(all_two_chars_occurencies('xxcaazz'))
['xx', 'xc', 'ca', 'aa', 'az', 'zz']
"""
for index, char in enumerate(string[:-1]):
yield char + string[index + 1]

def common_two_chars_occurences(a, b):
"""
Given 2 strings, a and b, return the number of the positions where
they contain the same length 2 substring.

>>> common_two_chars_occurences('xxcaazz', 'xxbaaz')
3
>>> common_two_chars_occurences('abc', 'abc')
2
>>> common_two_chars_occurences('abc', 'axc')
0
"""
equal_duets = 0
for a_duet, b_duet in zip(all_two_chars_occurencies(a),
all_two_chars_occurencies(b)):
if a_duet == b_duet:
equal_duets += 1
return equal_duets

if __name__ == "__main__":
doctest.testmod()


There is no such word as "occurencies". In any case, all_two_chars_occurencies is a very long name. I suggest pairwise_chars. Note that it could also be written in a style similar to the pairwise() recipe in Python's documentation.

In Python, explicit looping is slightly cumbersome. Fortunately, Python offers many ways to just do what you want as a "one-liner", without looping. Here's one approach, which uses a generator expression, and this technique to find its length.

def common_two_chars_occurences(a, b):
"""
Given 2 strings, a and b, return the number of the positions where
they contain the same length 2 substring.

>>> common_two_chars_occurences('xxcaazz', 'xxbaaz')
3
>>> common_two_chars_occurences('abc', 'abc')
2
>>> common_two_chars_occurences('abc', 'axc')
0
"""
return sum(1 for pair
in zip(pairwise_chars(a), pairwise_chars(b))
if pair[0] == pair[1])

• Note that you can sum booleans and use unpacking to get sum(left == right for left, right in zip(pairwise_chars(a), pairwise_chars(b))). My preference is actually sum(map(eq, pairwise_chars(a), pairwise_chars(b))) though (eq from operator). Commented Mar 28, 2015 at 10:16

You should refactor further writing an equal_at_same_index function:

def equal_at_same_index(list_1, list_2):
"""
>>> equal_at_same_index("abcde", "xxcae")
2
>>> equal_at_same_index("qwerty", "xqwerty")
0
"""
return sum((i == j for i, j in zip(list_1, list_2)))

def common_two_chars_occurences(a, b):
"""
Given 2 strings, a and b, return the number of the positions where
they contain the same length 2 substring.

>>> common_two_chars_occurences("xxcaazz", "xxbaaz")
3
>>> common_two_chars_occurences("abc", "abc")
2
>>> common_two_chars_occurences("abc", "axc")
0
"""
return equal_at_same_index(all_two_chars_occurencies(a),
all_two_chars_occurencies(b))