2010-06-16 1 views
0

В настоящее время у меня есть код python, который я бы хотел портировать на C++, поскольку он в настоящее время медленнее, чем мне хотелось бы. Проблема в том, что я использую словарь в нем, где ключ представляет собой кортеж, состоящий из объекта и строки (например, (obj, «word»)). Как я могу написать что-то подобное на C++? Может быть, мой алгоритм ужасен, и есть способ сделать это быстрее, не прибегая к C++?Как реализовать словарь «с кортежем Python» в качестве ключа на C++?

Полный алгоритм для ясности. Словарь «post_score» является проблемой.

def get_best_match_best(search_text, posts): 
    """ 
    Find the best matches between a search query "search_text" and any of the 
    strings in "posts". 

    @param search_text: Query to find an appropriate match with in posts. 
    @type search_text: string 
    @param posts: List of candidates to match with target text. 
    @type posts: [cl_post.Post] 
    @return: Best matches of the candidates found in posts. The posts are ordered 
    according to their rank. First post in list has best match and so on. 
    @returntype: [cl_post.Post] 
    """ 
    from math import log 

    search_words = separate_words(search_text) 
    total_number_of_hits = {} 
    post_score = {} 
    post_size = {} 
    for search_word in search_words: 
     total_number_of_hits[search_word] = 0.0 
     for post in posts: 
      post_score[(post, search_word)] = 0.0 
      post_words = separate_words(post.text) 
      post_size[post] = len(post_words) 
      for post_word in post_words: 
       possible_match = abs(len(post_word) - len(search_word)) <= 2 
       if possible_match: 
        score = calculate_score(search_word, post_word) 
        post_score[(post, search_word)] += score 
        if score >= 1.0: 
         total_number_of_hits[search_word] += 1.0 

    log_of_number_of_posts = log(len(posts)) 
    matches = [] 
    for post in posts: 
     rank = 0.0 
     for search_word in search_words: 
      rank += post_score[(post, search_word)] * \ 
        (log_of_number_of_posts - log(1.0 + total_number_of_hits[search_word])) 
     matches.append((rank/post_size[post], post)) 
    matches.sort(reverse=True) 
    return [post[1] for post in matches] 
+2

Вы еще пробовали Cython? –

+0

Серьезно чувак, если код уже без ошибок, почему бы не использовать существующие инструменты? Видите ли, Джо Польски не рекомендует переписывать. –

+1

@ Хамиш Грубиджан: кто такой Джо Польски, и почему меня должно волновать то, что он рекомендует? – sbk

ответ

3

map<pair<..., string>, ...> Если вы чертовски используете C++ для этого.

+0

Если бы MdaG был действительно адским, я думаю, что он использовал бы капсюль. – Ken

+0

Спасибо, пара была тем, чего мне не хватало. :-) И я не проклят, если я могу использовать Cython или лучший алгоритм, который еще лучше. :-) – MdaG

2

на этот раз вы вызываете отдельные_словы (post.text) для каждого слова поиска в search_words. Вы должны называть separ_words только один раз для каждого post в posts.

То есть, вместо:

for search_word in search_words: 
    for post in posts: 
     # do heavy work 

вместо него вы должны иметь:

for post in posts: 
    # do the heavy works 
    for search_word in search_words: 
     ... 

Если, как я подозревал, что separate_words сделать много струнных манипуляций, не забывайте, что строка манипуляции относительно дороги в python, поскольку строка неизменна.

Еще одно усовершенствование, которое вы можете сделать, заключается в том, что вам не нужно сравнивать каждое слово в search_words с каждым словом в post_words. Если вы сохраните отсортированные по длине слова search_words и post_words, то вы можете использовать технику раздвижного окна. В принципе, поскольку search_word будет соответствовать только сообщению_слову, если разница в их длине меньше 2, вам нужно только проверить среди двух разностей различий в окне, тем самым сократив количество проверяемых слов, например:

search_words = sorted(search_words, key=len) 
g_post_words = collections.defaultdict(list) # this can probably use list of list 
for post_word in post_words: 
    g_post_words[len(post_word)].append(post_word) 

for search_word in search_words: 
    l = len(search_word) 
    # candidates = itertools.chain.from_iterable(g_post_words.get(m, []) for m in range(l - 2, l + 3)) 
    candidates = itertools.chain(g_post_words.get(l - 2, []), 
           g_post_words.get(l - 1, []), 
           g_post_words.get(l , []), 
           g_post_words.get(l + 1, []), 
           g_post_words.get(l + 2, []) 
           ) 
    for post_word in candidates: 
     score = calculate_score(search_word, post_word) 
     # ... and the rest ... 

(этот код, вероятно, не будет работать как есть, это просто проиллюстрировать идею)

+0

Это ценный вклад, и вы правы. Я не знаком с itertools, но сейчас самое подходящее время для чтения. Спасибо. :) – MdaG

Смежные вопросы