Как следующая модель Encoder-Decoder генерирует выходные данные, отличающиеся от входного?

IMO, Ben Voigt начал с хорошей базовой идеи, но я бы предостерег от его формулировки слишком буквально.

В частности, мне не нравится идея поиска строки в наборе, а затем добавление это к вашему набору, если его нет, и добавив его в вывод, если он присутствует. Это в основном означает, что каждый раз, когда мы сталкиваемся с новым словом, мы дважды ищем наш набор существующих слов, один раз, чтобы проверить, присутствует ли слово, и снова вставить его, потому что это не так. Большая часть этого поиска будет по существу идентичной - если какой-то другой поток не изменяет структуру в промежуточный период (что может привести к состоянию гонки).

Вместо этого я начал с попытки добавить его к набору слов, которые вы видели. Это возвращает pair<iterator, bool>, а bool установлен на true тогда и только тогда, когда значение было вставлено - то есть ранее не было. Это позволяет нам консолидировать поиск существующей строки и вставить новую строку вместе в одну вставку:

while (input >> word)
    if (!(existing.insert(word)).second)
        output.insert(word);

Это также очищает поток настолько, что довольно легко включить тест в функтор, который мы можем использовать с std::remove_copy_if, чтобы получить наши результаты совершенно напрямую:

#include <set>
#include <iterator>
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>

class show_copies {
    std::set<std::string> existing;
public:
    bool operator()(std::string const &in) {
        return existing.insert(in).second;
    }
};

int main() {
    std::vector<std::string> words{ "words", "words", "are", "fun", "fun" };
    std::set<std::string> result;

    std::remove_copy_if(words.begin(), words.end(),
        std::inserter(result, result.end()), show_copies());

    for (auto const &s : result)
        std::cout << s << "\n";
}

В зависимости от того, насколько я больше заботился о простоте или скорости выполнения кода, я мог бы использовать std::vector вместо set для результата и используйте std::sort, а затем std::unique_copy, чтобы получить окончательный результат. В таком случае я, вероятно, также заменил бы std::set внутри show_copies на std::unordered_set:

#include <unordered_set>
#include <iterator>
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>

class show_copies {
    std::unordered_set<std::string> existing;
public:
    bool operator()(std::string const &in) {
        return existing.insert(in).second;
    }
};

int main() {
    std::vector<std::string> words{ "words", "words", "are", "fun", "fun" };
    std::vector<std::string> intermediate;

    std::remove_copy_if(words.begin(), words.end(),
        std::back_inserter(intermediate), show_copies());

    std::sort(intermediate.begin(), intermediate.end());
    std::unique_copy(intermediate.begin(), intermediate.end(),
        std::ostream_iterator<std::string>(std::cout, "\n"));
}

Это немного сложнее (одна целая линия длиннее!), Но, вероятно, быть значительно быстрее, когда / если количество слов становится очень большим. Также обратите внимание, что я использую std::unique_copy в первую очередь для получения видимого вывода. Если вы хотите получить результат в коллекции, вы можете использовать стандартную уникальную / стирающую идиому для получения уникальных элементов в intermediate.

0
задан wilkinsmicawber 17 January 2019 в 04:16
поделиться