Найти похожие элементы в списке словарей на основе значений

Я хочу сопоставить аналогичные статьи из базы данных Django на основе тегов, которые хранятся в списке словаря следующим образом:

myarticle = {'pk': 17, 'tags': [0, 1, 0, 1, 0]}
allarticles = [{'pk': 1, 'tags': [0, 0, 0, 1, 0]}, 
               {'pk': 2, 'tags': [0, 1, 0, 1, 0]},
               {'pk': 3, 'tags': [1, 1, 0, 0, 0]},
               {'pk': 4, 'tags': [1, 0, 1, 0, 1]},
               {'pk': 5, 'tags': [0, 0, 0, 0, 1]}]

Какой самый удобный способ получить список обратно, который ранжирует количество совпадающих тегов на основе входной статьи. Ожидаемый результат:

result = [2, 1, 3, 5, 4]

2 ответа

Ты можешь использовать sorted:

myarticle = {'pk': 17, 'tags': [0, 1, 0, 1, 0]}
allarticles = [{'pk': 1, 'tags': [0, 0, 0, 1, 0]}, 
           {'pk': 2, 'tags': [0, 1, 0, 1, 0]},
           {'pk': 3, 'tags': [1, 1, 0, 0, 0]},
           {'pk': 4, 'tags': [1, 0, 1, 0, 1]},
           {'pk': 5, 'tags': [0, 0, 0, 0, 1]}]
new_articles = sorted(allarticles, key=lambda x:sum(a == b for a, b in zip(myarticle['tags'], x['tags'])), reverse=True)
final_results = [i['pk'] for i in new_articles]

Выход:

[2, 1, 3, 5, 4]

Вы можете использовать стороннюю NumPy для векторизованного решения, через numpy.argsort,

Для большего списка ввода это должно быть более эффективным:

allarticles = allarticles*10000

import numpy as np

def jp(myarticle, allarticles):
    arr = np.argsort((np.array([d['tags'] for d in allarticles]) == myarticle['tags']).sum(1))[::-1]
    return [allarticles[i]['pk'] for i in arr]

def ajax(myarticle, allarticles):
    new_articles = sorted(allarticles, key=lambda x:sum(a == b for a, b in zip(myarticle['tags'], x['tags'])), reverse=True)
    return [i['pk'] for i in new_articles]

%timeit jp(myarticle, allarticles)    # 49.3 ms per loop
%timeit ajax(myarticle, allarticles)  # 112 ms per loop
Другие вопросы по тегам