У меня есть список, как показано ниже:
Test = ['ASDFGH', 'QWERTYU', 'ZXCVB']
И список ссылок вот так:
Ref = ['ASDFGY', 'QWERTYI', 'ZXCAA']
Я хочу извлечь значения из Test
если они имеют N или меньше символов, отличных от любого из элементов в Ref
.
Например, если N = 1, должны выводиться только первые два элемента теста. Если N = 2, все три элемента соответствуют этим критериям и должны быть возвращены.
Следует отметить, что я ищу одинаковые значения длины символов (ASDFGY → ASDFG не работает для N = 1), поэтому я хочу что-то более эффективное, чем levensthein distance.
У меня более 1000 значений в ref и несколько сотен миллионов тестов, поэтому эффективность является ключевой.
Новый модуль regex
предлагает возможность "нечеткого" совпадения:
import regex as re
Test = ['ASDFGH', 'QWERTYU', 'ZXCVB']
Ref = ['ASDFGY', 'QWERTYI', 'ZXCAA', 'ASDFGI', 'ASDFGX']
for item in Test:
rx = re.compile('(' + item + '){s<=3}')
for r in Ref:
if rx.search(r):
print(rf'{item} is similar to {r}')
Это дает
ASDFGH is similar to ASDFGY
ASDFGH is similar to ASDFGI
ASDFGH is similar to ASDFGX
QWERTYU is similar to QWERTYI
ZXCVB is similar to ZXCAA
Вы можете управлять им через часть {s<=3}
которая допускает три или менее замены.
pairs = [(origin, difference)
for origin in Test
for rx in [re.compile(rf"({origin}){{s<=3}}")]
for difference in Ref
if rx.search(difference)]
Это
Test = ['ASDFGH', 'QWERTYU', 'ZXCVB']
Ref = ['ASDFGY', 'QWERTYI', 'ZXCAA', 'ASDFGI', 'ASDFGX']
следующий результат:
[('ASDFGH', 'ASDFGY'), ('ASDFGH', 'ASDFGI'),
('ASDFGH', 'ASDFGX'), ('QWERTYU', 'QWERTYI'),
('ZXCVB', 'ZXCAA')]
Использование выражения поколения с sum
:
Test = ['ASDFGH', 'QWERTYU', 'ZXCVB']
Ref = ['ASDFGY', 'QWERTYI', 'ZXCAA']
from collections import Counter
def comparer(x, y, n):
return (len(x) == len(y)) and (sum(i != j for i, j in zip(x, y)) <= n)
res = [a for a, b in zip(Ref, Test) if comparer(a, b, 1)]
print(res)
['ASDFGY', 'QWERTYI']
Использование difflib
Демо - версия:
import difflib
N = 1
Test = ['ASDFGH', 'QWERTYU', 'ZXCVB']
Ref = ['ASDFGY', 'QWERTYI', 'ZXCAA']
result = []
for i,v in zip(Test, Ref):
c = 0
for j,s in enumerate(difflib.ndiff(i, v)):
if s.startswith("-"):
c += 1
if c <= N:
result.append( i )
print(result)
Выход:
['ASDFGH', 'QWERTYU']