Найти значения в списке, которые отличаются от списка ссылок до N символов

1

У меня есть список, как показано ниже:

Test = ['ASDFGH', 'QWERTYU', 'ZXCVB']

И список ссылок вот так:

Ref = ['ASDFGY', 'QWERTYI', 'ZXCAA']

Я хочу извлечь значения из Test если они имеют N или меньше символов, отличных от любого из элементов в Ref.

Например, если N = 1, должны выводиться только первые два элемента теста. Если N = 2, все три элемента соответствуют этим критериям и должны быть возвращены.

Следует отметить, что я ищу одинаковые значения длины символов (ASDFGY → ASDFG не работает для N = 1), поэтому я хочу что-то более эффективное, чем levensthein distance.

У меня более 1000 значений в ref и несколько сотен миллионов тестов, поэтому эффективность является ключевой.

Теги:
string

3 ответа

1

Новый модуль 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')]
  • 0
    Почему это не дает ZXCVB похож на ZXCAA? Вы допустили до 3 замен, и это только 2 замены.
  • 0
    @JackArnestad: Ты прав. Обновлено, вам нужно поставить круглые скобки вокруг элемента, в противном случае был проанализирован только последний символ.
1

Использование выражения поколения с 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']
  • 0
    Это работает только для вариаций в конце последовательности? Возможно, я должен был быть более откровенным об этом, но разница может быть где угодно в строке.
  • 0
    @JackArnestad, смотрите обновление, теперь это должно быть хорошо.
1

Использование 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']

Ещё вопросы

Сообщество Overcoder
Наверх
Меню