我试图通过比较字符串的长度来比较插入到我的集合之前的字符串。应首先插入最短的字符串。我不知道发生了什么,但有些话不在场上。
我的代码:
#include <iostream>
#include <string>
#include <set>
struct compare {
bool operator() (const string& a, const string& b) const{
return a.size() < b.size();
}
};
template<typename T>
void print(const T& t){
for(auto& it : t)
cout << it << endl;
}
int main() {
string word;
set<string, compare> c;
while(cin >> word)
c.insert(word);
print(c);
return 0;
}
以下是要插入的测试词
Apple
Apricots
Avocado
Durian
Fig
Tangerine/Clementine
Kumquat
Lemon
Pear
Prunes
Raspberries
Strawberries
Watermelon
这是OUTPUT
Fig
Pear
Apple
Durian
Avocado
Apricots
Watermelon
Raspberries
Strawberries
Tangerine/Clementine
它按预期工作,但显然有些词语缺失 喜欢:
Kumquat
Lemon
Prunes
答案 0 :(得分:4)
std::set不能包含重复项。在这种情况下,它不能有两个相同长度的字符串。也许你会用std::multiset做得更好?
#include <iostream>
#include <string>
#include <set>
struct compare {
bool operator() (const std::string& a, const std::string& b) const{
return a.size() < b.size();
}
};
template<typename T>
void print(const T& t){
for(auto& it : t)
std::cout << it << std::endl;
}
int main() {
std::string word;
std::multiset<std::string, compare> c; // multiset!!!
while(std::cin >> word)
c.insert(word);
print(c);
return 0;
}
<强>输出:强>
Fig
Pear
Apple
Lemon
Durian
Prunes
Avocado
Kumquat
Apricots
Watermelon
Raspberries
Strawberries
Tangerine/Clementine
注意:此解决方案允许重复的字符串长度,以便字符串可以按长度排序。但这意味着它还允许重复的字符串值,以便相同的字符串可以出现多次。
答案 1 :(得分:3)
设置不允许重复元素。如果集合的比较函数是less
,则集合使用!less(a, b) && !less(b, a)
来确定两个元素是否相同(因此是重复的)。
默认情况下,集合使用的比较函数是<
运算符。所以当你这样做时:
set::set<int> s;
int x = 42, y = 42;
s.insert(x);
s.insert(y);
仅插入一个元素的原因是x < y
为false且y < x
也为false,因此集合确定x == y
并忽略第二个插入。
但是通过你定义的比较函数,所有相同长度的字符串都被认为是相同的。一旦字符串中存在长度为N
的字符串,您尝试插入的所有未来字符串N
将不会被插入(因为该集合认为它们已经存在)。
std::set<string, compare> s;
s.insert("abc");
s.insert("def");
less("abc", "def")
为false且less("def", "abc")
为false,因此该集合将"abc"
和"def"
解释为相同。
您可以使用打破平局less
功能解决此问题,例如:
bool operator() (const string& a, const string& b) const{
if (a.size() == b.size()) {
return a < b;
}
return a.size() < b.size();
}
这将首先按大小对字符串进行排序,但通过按字典顺序排序来断开连接。现在两个字符串不会被认为是相等的,除非它们实际上是相同的。
答案 2 :(得分:2)
您是否注意到集合中的所有条目都有不同的长度?
那是因为compare
函数决定了某些内容是否被认为是该集合中已有内容的重复:
如果key_comp以反射方式返回false(即无论元素作为参数传递的顺序),则集合中的两个元素被认为是等效的。
因为,对于两个长度相同的单词,key_comp(word1, word2)
和key_comp(word2, word1)
都返回false,单词被认为是相同的,因此第二个单词不会插入到集合中。
您可以通过略微修改您的功能来解决此问题:
bool operator() (const string& a, const string& b) const {
if (a.size() == b.size()) return a < b;
return a.size() < b.size();
}
执行基于内容的比较(而不是基于长度),其中两个项目的长度相同)。
答案 3 :(得分:2)
解决这个问题的第一步应该是简化,在这种情况下,删除输入作为潜在原因。这样做表明问题不是由数据源引起的。因此,让我们看看是否存储了值:
#include <iostream>
#include <string>
#include <set>
struct compare {
bool operator() (const std::string& a, const std::string& b) const{
return a.size() < b.size();
}
};
template<typename T>
void print(const T& t){
for(auto& it : t)
std::cout << it << "\n";
}
template<typename T>
void insert(T& t, const char* value)
{
t.insert(value);
std::cout << "After inserting " << value << "\n";
print(t);
std::cout << "\n";
}
int main() {
std::set<std::string, compare> c;
insert(c, "Apple");
insert(c, "Apricots");
insert(c, "Avocado");
insert(c, "Durian");
insert(c, "Fig");
insert(c, "Tangerine/Clementine");
insert(c, "Kumquat");
insert(c, "Lemon");
insert(c, "Pear");
insert(c, "Prunes");
insert(c, "Raspberries");
insert(c, "Strawberries");
insert(c, "Watermelon");
print(c);
return 0;
}
这些价值不会被存储,但似乎我们可以解决这个问题:
insert(c, "Apple");
insert(c, "Lemon");
std::set::insert
会返回一些可能有用的信息:http://www.cplusplus.com/reference/set/set/insert/
auto result = t.insert(value);
我们对result.second感兴趣。对于成功插入将是真实的(1),对于失败则为假(0)。
After inserting Apple. inserted? 1
Apple
After inserting Lemon. inserted? 0
Apple
您的比较运算符导致集合认为这两个值相等。 std::set
使用<
运算符两次确定等效性:
if (!cmp(a, b))
if (!cmp(b, a))
// equal;
您可能想要使用:
struct compare {
bool operator() (const string& a, const string& b) const{
if (a.size() < b.size())
return true;
if (a.size() == b.size() && a.compare(b) < 0)
return true;
return false;
}
};
完整代码:
#include <iostream>
#include <string>
#include <set>
struct compare {
bool operator() (const std::string& a, const std::string& b) const{
if (a.size() < b.size())
return true;
if (a.size() == b.size() && a.compare(b) < 0)
return true;
return false;
}
};
template<typename T>
void print(const T& t){
for(auto& it : t)
std::cout << it << "\n";
}
template<typename T>
void insert(T& t, const char* value)
{
auto result = t.insert(value);
std::cout << "After inserting " << value << ". inserted? " << result.second << "\n";
print(t);
std::cout << "\n";
}
int main() {
std::set<std::string, compare> c;
insert(c, "Apple");
insert(c, "Lemon");
insert(c, "Fig");
insert(c, "Kumquat");
print(c);
return 0;
}
输出:
After inserting Apple. inserted? 1
Apple
After inserting Lemon. inserted? 1
Apple
Lemon
After inserting Fig. inserted? 1
Fig
Apple
Lemon
After inserting Kumquat. inserted? 1
Fig
Apple
Lemon
Kumquat
答案 4 :(得分:1)
如果您不是特别关心最有效的解决方案,只关心插入的顺序。这是一个简单的解决方案:排序然后插入。
#include <vector>
#include <set>
#include <algorithm>
#include <iostream>
std::set<std::string> InsertByLength(std::vector<std::string> src)
{
std::sort(src.begin(), src.end(), [](const std::string& a, const std::string& b)
{
return a.size() < b.size();
});
std::set<std::string> ret;
for(auto s : src) {
std::cout << s << std::endl;
ret.insert(s);
}
return ret;
}
int main()
{
auto result = InsertByLength({
"Apple", "Apricots", "Avocado", "Durian", "Fig", "Tangerine/Clementine",
"Kumquat", "Lemon", "Pear", "Prunes" "Raspberries", "Strawberries",
"Watermelon"});
std::cout << "Inserted: " << result.size() << " elements\n";
return 0;
}