Как реализовать словарь "с кортежем Python" в качестве ключа в C ++? - PullRequest
0 голосов
/ 16 июня 2010

В настоящее время у меня есть некоторый код на Python, который я хотел бы перенести на C ++, поскольку в настоящее время он работает медленнее, чем хотелось бы. Проблема в том, что я использую в нем словарь, ключом которого является кортеж, состоящий из объекта и строки (например, (obj, "word")). Как же мне написать что-то похожее на C ++? Может быть, мой алгоритм ужасен, и есть какой-то способ сделать его быстрее, не прибегая к 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 ]

3 голосов
/ 16 июня 2010

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

2 голосов
/ 16 июня 2010

за один раз, вы вызываете Отдельные слова (post.text) для каждого слова поиска в словах поиска.Вы должны вызывать Отдельные слова только один раз для каждого 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:
        ...

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

Еще одно улучшение, которое вы можете сделать, это то, что вы не делаетенужно сравнить каждое слово в search_words с каждым словом в post_words.Если вы сохраняете массив search_words и post_words, отсортированный по длине слова, вы можете использовать технику скользящего окна.По сути, так как search_word будет соответствовать post_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 ...

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...