C++ 如何在std::vector中查找重复项<;字符串>;并返回他们的列表?
如果我有一个向量,比如:C++ 如何在std::vector中查找重复项<;字符串>;并返回他们的列表?,c++,stl,functor,C++,Stl,Functor,如果我有一个向量,比如: Vec1 = "words", "words", "are", "fun", "fun" 结果列表:“乐趣”、“词语” 我试图确定哪些单词是重复的,并返回它们的1个副本的字母顺序向量。我的问题是,我甚至不知道从哪里开始,我发现唯一接近它的东西是std::unique\u copy,它不能完全满足我的需要。具体来说,我输入的是std::vector,但输出的是std::list。如果需要,我可以用函子 至少有人能把我推向正确的方向吗?我已经试过阅读stl文档,但我现在只
Vec1 = "words", "words", "are", "fun", "fun"
结果列表:“乐趣”、“词语”
我试图确定哪些单词是重复的,并返回它们的1个副本的字母顺序向量。我的问题是,我甚至不知道从哪里开始,我发现唯一接近它的东西是std::unique\u copy
,它不能完全满足我的需要。具体来说,我输入的是std::vector
,但输出的是std::list
。如果需要,我可以用函子
至少有人能把我推向正确的方向吗?我已经试过阅读stl文档,但我现在只是“大脑”被阻塞了 您可以使用std::map来计算出现次数,然后依靠std::list::sort对生成的单词列表进行排序,从而得到一个非常干净的实现。例如:
std::list<std::string> duplicateWordList(const std::vector<std::string>& words) {
std::map<std::string, int> temp;
std::list<std::string> ret;
for (std::vector<std::string>::const_iterator iter = words.begin(); iter != words.end(); ++iter) {
temp[*iter] += 1;
// only add the word to our return list on the second copy
// (first copy doesn't count, third and later copies have already been handled)
if (temp[*iter] == 2) {
ret.push_back(*iter);
}
}
ret.sort();
return ret;
}
std::list duplicateWordList(const std::vector&words){
标准:映射温度;
std::列表ret;
for(std::vector::const_iterator iter=words.begin();iter!=words.end();++iter){
温度[*iter]+=1;
//只需在第二份上的退货清单中添加该词
//(第一份不算,第三份及以后的副本已经处理完毕)
如果(温度[*iter]==2){
反向推送(*iter);
}
}
ret.sort();
返回ret;
}
在那里使用std::map似乎有点浪费,但它完成了任务
std::无序集
由于您希望每个副本只在结果中列出一次,因此您也可以使用哈希集(而不是列表)作为结果。在我看来,Ben Voigt从一个很好的基本想法开始,但我要提醒您不要将他的措辞过于字面化 特别是,我不喜欢在集合中搜索字符串,如果它不存在则将其添加到集合中,如果它存在则将其添加到输出中。这基本上意味着每次我们遇到一个新词时,我们都会搜索我们现有的词集两次,一次是检查一个词是否存在,另一次是插入它,因为它不存在。大部分搜索本质上是相同的——除非其他线程在此期间改变结构(这可能会给出竞争条件) 相反,我会先尝试将它添加到您看到的一组单词中。它返回一个
对
,bool
设置为true
,当且仅当插入了值,即之前不存在时。这使我们可以将搜索现有字符串和插入新字符串合并为一个插入:
while (input >> word)
if (!(existing.insert(word)).second)
output.insert(word);
这也足够清理流,可以很容易地将测试转换为一个函子,然后我们可以将它与std::remove\u copy\u一起使用,如果
直接生成结果:
#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::unique_copy主要是为了产生可见的输出。如果您只想在集合中获得结果,可以使用标准的unique/erase惯用法在intermediate
中获得3行中的唯一项(不包括向量和列表创建,也不包括可读性名称中多余的换行):
向量向量{“单词”、“单词”、“是”、“有趣”、“有趣”};
列表输出;
排序(vec.begin(),vec.end());
设置uvec(vec.begin(),vec.end());
设置差异(向量开始(),向量结束(),
uvec.begin(),uvec.end(),
背面插入器(输出);
编辑
对解决方案的解释:
set_difference()
uvec
集将自动对元素进行排序,并消除重复项
输出
列表将由vec-uvec
的元素填充
这里有一个比其他人提出的更好的算法:
#include <algorithm>
#include <vector>
template<class It> It unique2(It const begin, It const end)
{
It i = begin;
if (i != end)
{
It j = i;
for (++j; j != end; ++j)
{
if (*i != *j)
{ using std::swap; swap(*++i, *j); }
}
++i;
}
return i;
}
int main()
{
std::vector<std::string> v;
v.push_back("words");
v.push_back("words");
v.push_back("are");
v.push_back("fun");
v.push_back("words");
v.push_back("fun");
v.push_back("fun");
std::sort(v.begin(), v.end());
v.erase(v.begin(), unique2(v.begin(), v.end()));
std::sort(v.begin(), v.end());
v.erase(unique2(v.begin(), v.end()), v.end());
}
#包括
#包括
模板It unique2(It常量开始,It常量结束)
{
它i=开始;
如果(i!=结束)
{
它j=i;
对于(++j;j!=end;++j)
{
如果(*i!=*j)
{使用std::swap;swap(*++i,*j);}
}
++一,;
}
返回i;
}
int main()
{
std::向量v;
v、 推回(“文字”);
v、 推回(“文字”);
v、 推回(“are”);
v、 推回(“乐趣”);
v、 推回(“文字”);
v、 推回(“乐趣”);
v、 推回(“乐趣”);
排序(v.begin(),v.end());
v、 擦除(v.begin(),unique2(v.begin(),v.end());
排序(v.begin(),v.end());
v、 擦除(unique2(v.begin()、v.end()、v.end());
}
它更好,因为它只需要代码>交换< /COD>没有辅助<代码>向量< /代码>用于存储,这意味着它对于C++的早期版本将是最佳的,并且它不需要元素是可复制的。 如果你更聪明,我想你也可以避免对向量进行两次排序。
就地(无额外存储)。没有字符串复制(除了到结果列表)。一次排序+一次传递:#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
vector<string> vec{"words", "words", "are", "fun", "fun"};
list<string> dup;
sort(vec.begin(), vec.end());
const string empty{""};
const string* prev_p = ∅
for(const string& s: vec) {
if (*prev_p==s) dup.push_back(s);
prev_p = &s;
}
for(auto& w: dup) cout << w << ' ';
cout << '\n';
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
int main(){
向量向量{“单词”、“单词”、“是”、“有趣”、“有趣”};
列出dup;
排序(vec.begin(),vec.end());
常量字符串为空{“”};
常量字符串*prev_p=&empty;
for(常量字符串&s:vec){
如果(*prev_p==s)重复向后推;
上一个p=&s;
}
for(auto&w:dup)cout如果您使用std::set
来存储单词,而不是向量,那么您可以免费获得唯一性和排序。既然您希望它按字母顺序排列,我想您不会介意它是否被排序?
#include <algorithm>
#include <vector>
template<class It> It unique2(It const begin, It const end)
{
It i = begin;
if (i != end)
{
It j = i;
for (++j; j != end; ++j)
{
if (*i != *j)
{ using std::swap; swap(*++i, *j); }
}
++i;
}
return i;
}
int main()
{
std::vector<std::string> v;
v.push_back("words");
v.push_back("words");
v.push_back("are");
v.push_back("fun");
v.push_back("words");
v.push_back("fun");
v.push_back("fun");
std::sort(v.begin(), v.end());
v.erase(v.begin(), unique2(v.begin(), v.end()));
std::sort(v.begin(), v.end());
v.erase(unique2(v.begin(), v.end()), v.end());
}
#include <string>
#include <vector>
#include <list>
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
vector<string> vec{"words", "words", "are", "fun", "fun"};
list<string> dup;
sort(vec.begin(), vec.end());
const string empty{""};
const string* prev_p = ∅
for(const string& s: vec) {
if (*prev_p==s) dup.push_back(s);
prev_p = &s;
}
for(auto& w: dup) cout << w << ' ';
cout << '\n';
}