IMO,Ben Voigt 从一个很好的基本想法开始,但我会告诫不要将他的措辞过于字面化。
特别是,我不喜欢在集合中搜索字符串,如果不存在则将其添加到您的集合中,如果存在则将其添加到输出中的想法。这基本上意味着每次我们遇到一个新词时,我们都会搜索我们的现有词集两次,一次是检查一个词是否存在,一次是因为它不存在而插入它。大多数搜索基本上是相同的——除非其他一些线程在过渡期间改变结构(这可能会产生竞争条件)。
相反,我会首先尝试将它添加到您所看到的单词集中。这将返回 a 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";
}
根据我是否更关心代码的简单性或执行速度,我可能会使用 anstd::vector
而不是set
for 结果,并使用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
.