Удалить номера из списка, если они не содержатся в подстроке другого списка - PullRequest
0 голосов
/ 02 ноября 2018

Вот моя ситуация:

У меня есть один список названий продуктов, таких как:
BLUEAPPLE, GREENBUTTON20, 400100DUCK20 (len = 9000)
и список официальных названий предметов, таких как:
BLUEAPPLE, GREENBUTTON, 100DUCK. (len = 2700)

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

Я нашел решение, но проблема в том, что оно работает очень медленно.

def remove_nums(product):
    if bool(re.search('\d'), product):
        for item in item_nums_list:
            if item in product_name:
                substrings = [u for x in product_name.split(item) for u in (x, item)][:-1]
                no_num_list = [re.sub('(\d+)', '', substring) if substring not in item else substring for substring in substrings]
                return ''.join(no_num_list)
        return re.sub('(\d+)', '', product)
    else:
        return product

Пример:

product_name = '400100DUCK20'
item = '100DUCK'
substrings = ['400','100DUCK','20']
no_num_list = ['','100OG','']
returns '100DUCK'

Эта функция отображена таким образом, что она циклически повторяется для каждого продукта в списке продуктов.

Я пытался найти способ использовать лямбды здесь, карты, аппликации и т. Д., Но не могу обернуть это вокруг себя. Каков был бы самый эффективный способ выполнить то, что я пытаюсь сделать, с помощью прямых списков или в пандах? Кроме того, я получаю эти списки товаров и продуктов из базы данных postgres, так что если вы думаете, что в psql было бы быстрее, я бы пошел по этому пути.

Ответы [ 2 ]

0 голосов
/ 02 ноября 2018

Попробуйте это:

def remove_nums(product):
    if re.search('\d', product):
        for item in item_nums_list:
            if item in product:
                return item
        return re.sub('(\d+)', '', product)
else:
    return product

Также убедитесь, что вы используете обычный интерпретатор python. IPython и другие интерпретаторы с функциями отладки НАМНОГО медленнее, чем обычный интерпретатор.

Возможно, вы захотите сначала выполнить некоторые операции над множествами. Вот небольшой пример:

product_set = set(product_list)
item_number_set = set(item_number_list)

# these are the ones that match straight away
product_matches = product_set & item_number_set

# now we can search through the substrings of ones that don't match
non_matches = product_set - item_number_set
for product in non_matches:
    for item_number in item_number_set:
        if item_number in product:
            product_matches.add(product)
            break

# product_matches is now a set of all unique codes contained in both lists by "fuzzy match"
print(product_matches)

Вы как бы теряете порядок, в котором они появились, но, возможно, вы можете найти способ изменить это для своего использования.

0 голосов
/ 02 ноября 2018

difflib.get_close_matches() по крайней мере поможет очистить ваш код и, вероятно, будет работать быстрее.

import difflib
p_names = ['BLUEAPPLE', 'GREENBUTTON20', '400100DUCK20']
i_names = ['BLUEAPPLE', 'GREENBUTTON', '100DUCK']
for p in p_names:
    print(difflib.get_close_matches(p, i_names))

>>> 
['BLUEAPPLE']
['GREENBUTTON']
['100DUCK']
>>> 

По-прежнему будет проводиться много сравнений, оно должно сопоставлять каждую строку в p_names с каждой строкой в ​​i_names.


Аналогично вашему подходу с использованием регулярных выражений для поиска соответствия:

import re
for p in p_names:
    for i in i_names:
        if re.search(i, p):
            print(i)
            # stop looking
            break
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...