C++ 对集合进行排序<;字符串>;以长度为基础
我的问题是关于 我想在lambda表达式作为谓词的帮助下,对C++ 对集合进行排序<;字符串>;以长度为基础,c++,stl,lambda,c++11,set,C++,Stl,Lambda,C++11,Set,我的问题是关于 我想在lambda表达式作为谓词的帮助下,对集合执行sort()操作 我的代码是 #include <set> #include <string> #include <iostream> #include <algorithm> int main() { using namespace std; string s = "abc"; set<string> results; do { for (in
集合执行sort()
操作
我的代码是
#include <set>
#include <string>
#include <iostream>
#include <algorithm>
int main() {
using namespace std;
string s = "abc";
set<string> results;
do {
for (int n = 1; n <= s.size(); ++n) {
results.insert(s.substr(0, n));
}
} while (next_permutation(s.begin(), s.end()));
sort (results.begin(),results.end());[](string a, string b)->bool{
size_t alength = a.length();
size_t blength = b.length();
return (alength < blength);
});
for (set<string>::const_iterator x = results.begin(); x != results.end(); ++x) {
cout << *x << '\n';
}
return 0;
}
#包括
#包括
#包括
#包括
int main(){
使用名称空间std;
字符串s=“abc”;
设定结果;
做{
对于(int n=1;n布尔){
尺寸长度=a.长度();
尺寸?混合度=b.长度();
返回值(alength集合中的排列是固定的,因此唯一可以使用的迭代器是const
迭代器
您需要先将结果
复制到向量
或deque
(或类似)中
不能对集合进行排序。集合总是按键排序(键本身就是元素)
更具体地说,std::sort
需要随机访问迭代器。std::set
提供的迭代器不是随机的。需要set
不提供的随机访问迭代器(它是一个双向迭代器)。如果您将代码更改为使用vector
,它将编译得很好。您可以通过提供自定义谓词来自定义集中元素的顺序,以确定添加元素相对于现有成员的顺序。集
定义为
template <
class Key,
class Traits=less<Key>,
class Allocator=allocator<Key>
>
class set
模板<
类密钥,
阶级特征=更少,
类分配器=分配器
>
类集
特质在哪里
提供函数的类型
对象,该对象可以比较两个元素
值作为排序键,以确定其
集合中的相对顺序。此
参数是可选的,二进制
谓词less是默认值
价值观
这是有背景的
在您的情况下,这意味着:
auto comp = [](const string& a, const string& b) -> bool
{ return a.length() < b.length(); };
auto results = std::set <string, decltype(comp)> (comp);
auto comp=[](常量字符串和a、常量字符串和b)->bool
{返回a.length()
请注意,这将导致具有相同字符串长度的set
元素被视为重复的元素,就我所能理解的预期结果而言,这不是您想要的。Edit:请注意,这实际上就是您正在搜索的元素,因为他以C++0x Lambda的形式内联了我在下面编写的C++03代码
另一个解决方案是定制std::set
排序函数:
struct MyStringLengthCompare
{
bool operator () (const std::string & p_lhs, const std::string & p_rhs)
{
const size_t lhsLength = p_lhs.length() ;
const size_t rhsLength = p_rhs.length() ;
if(lhsLength == rhsLength)
{
return (p_lhs < p_rhs) ; // when two strings have the same
// length, defaults to the normal
// string comparison
}
return (lhsLength < rhsLength) ; // compares with the length
}
} ;
std::set
已订购。。。
std::set
有它自己的顺序,一旦构建了它,就不应该更改它。因此,下面的代码:
int main(int argc, char* argv[])
{
std::set<std::string> aSet ;
aSet.insert("aaaaa") ;
aSet.insert("bbbbb") ;
aSet.insert("ccccccc") ;
aSet.insert("ddddddd") ;
aSet.insert("e") ;
aSet.insert("f") ;
outputSet(aSet) ;
return 0 ;
}
…但您可以自定义其排序功能
现在,如果需要,您可以使用自己的比较功能自定义设置:
struct MyStringLengthCompare
{
bool operator () (const std::string & p_lhs, const std::string & p_rhs)
{
const size_t lhsLength = p_lhs.length() ;
const size_t rhsLength = p_rhs.length() ;
if(lhsLength == rhsLength)
{
return (p_lhs < p_rhs) ; // when two strings have the same
// length, defaults to the normal
// string comparison
}
return (lhsLength < rhsLength) ; // compares with the length
}
} ;
集合现在将使用functorMyStringLengthCompare
对其项目进行排序,因此,此代码将输出:
- e
- f
- aaaaa
- bbbbb
- ccccccc
- ddddddd
但要小心订购错误!
创建自己的排序函数时,必须遵循以下规则:
如果(lhs
如果由于某种原因,您的排序函数不尊重它,您的手上就会有一个损坏的集合。std::set对于维护排序和变异列表非常有用。当集合本身在构建后不会发生太大变化时,使用向量会更快、更小
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
int main() {
using namespace std;
string s = "abc";
vector<string> results;
do {
for (size_t n = 1; n <= s.size(); ++n) {
results.push_back(s.substr(0, n));
}
} while (next_permutation(s.begin(), s.end()));
//make it unique
sort( results.begin(), results.end() );
auto end_sorted = unique( results.begin(), results.end() );
results.erase( end_sorted, results.end() );
//sort by length
sort (results.begin(),results.end());
[](string lhs, string rhs)->bool
{ return lhs.length() < rhs.length(); } );
for ( const auto& result: results ) {
cout << result << '\n';
}
}
#包括
#包括
#包括
#包括
int main(){
使用名称空间std;
字符串s=“abc”;
矢量结果;
做{
对于(尺寸n=1;n布尔)
{返回lhs.length() cout既然我编写了您正在使用的原始代码,也许我可以对其进行扩展…:)
struct cmp\u按长度{
模板
布尔运算符()(T常量和a、T常量和b){
返回a.length()
这将首先按长度进行比较,然后按值进行比较。修改集合定义:
set<string, cmp_by_length> results;
设置结果;
你可以走了:
int main() {
using namespace std;
string s = "abc";
typedef set<string, cmp_by_length> Results; // convenience for below
Results results;
do {
for (int n = 1; n <= s.size(); ++n) {
results.insert(s.substr(0, n));
}
} while (next_permutation(s.begin(), s.end()));
// would need to add cmp_by_length below, if I hadn't changed to the typedef
// i.e. set<string, cmp_by_length>::const_iterator
// but, once you start using nested types on a template, a typedef is smart
for (Results::const_iterator x = results.begin(); x != results.end(); ++x) {
cout << *x << '\n';
}
// of course, I'd rather write... ;)
//for (auto const &x : results) {
// cout << x << '\n';
//}
return 0;
}
intmain(){
使用名称空间std;
字符串s=“abc”;
typedef set Results;//为下文提供方便
结果;
做{
对于(int n=1;n我想问他为什么首先要将它们插入一个集合。@ybung:我想是为了删除重复项。其他人已经注意到不能对一个std::集合进行std::排序。此外,我认为);
就在lambda表达式应该是逗号之前。这会改变程序的行为。现在,集合只能包含一个任意给定长度的字符串,而不是任意给定值。您的输出有错误;要获得该结果,需要multiset
@Potatoswatter:问题作者的程序将忽略带有dif的字符串不同的内容,但长度相同。但作者没有描述程序的意图。只是它被窃听了。我猜原始程序的行为是错误的。这就是为什么我自己的比较函数处理“相同长度,不同内容”的情况。我将在我的回答中澄清这一点,其有趣的价值不在于比较函数的确切代码,而在于它的使用及其陷阱。@Potatoswatter:现在,如果你遵循链接,你会看到作者希望能够对相同长度的字符串进行排列,如“abc”、“bca”等。“仅长度”在这种情况下,比较功能对他没有帮助。这让我相信我在提供“长度和内容”时是正确的比较。@Potatoswatter:最后,但并非最不重要的一点,我想知道你的评论是否暗示我的代码和/或其输出是错误的。因此,为了澄清一切,我的代码在发布之前已经过测试,其输出是真实的。所以我的“输出没有错误”。啊,现在我看到了“默认到正常比较”case.+1.@Roger-由于包含代码,您的注释被篡改了,我想-我的答案已经表明它将导致字符串w的dup
struct cmp_by_length {
template<class T>
bool operator()(T const &a, T const &b) {
return a.length() < b.length() or (a.length() == b.length() and a < b);
}
};
set<string, cmp_by_length> results;
int main() {
using namespace std;
string s = "abc";
typedef set<string, cmp_by_length> Results; // convenience for below
Results results;
do {
for (int n = 1; n <= s.size(); ++n) {
results.insert(s.substr(0, n));
}
} while (next_permutation(s.begin(), s.end()));
// would need to add cmp_by_length below, if I hadn't changed to the typedef
// i.e. set<string, cmp_by_length>::const_iterator
// but, once you start using nested types on a template, a typedef is smart
for (Results::const_iterator x = results.begin(); x != results.end(); ++x) {
cout << *x << '\n';
}
// of course, I'd rather write... ;)
//for (auto const &x : results) {
// cout << x << '\n';
//}
return 0;
}