我的问题与this有关。
我希望借助lambda表达式作为谓词,对sort()
执行set
操作。
我的代码是
#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;
}
但错误的数量和类型非常复杂,我无法理解如何解决它们。有人能告诉我这段代码有什么不对。
答案 0 :(得分:8)
编辑:请注意,Steve Townsend's solution实际上是您正在搜索的那个,因为他将其编写为C ++ 0x Lambda,我将其编写为C ++ 03代码如下。
另一种解决方案是自定义std::set
排序功能:
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 ;
}
将输出以下结果:
- aaaaa
- bbbbb
- ccccccc
- ddddddd
- e
- f
现在,如果需要,您可以使用自己的比较功能自定义您的设置:
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
}
} ;
在这个比较函子中,我确实处理了“相同长度但不同内容意味着不同字符串”的情况,因为我相信(可能是错误地)原始程序中的行为是错误的。要在原始程序中编码行为,请从代码中删除if
块。
现在,您构建集合:
int main(int argc, char* argv[])
{
std::set<std::string, MyStringLengthCompare> aSet ;
aSet.insert("aaaaa") ;
aSet.insert("bbbbb") ;
aSet.insert("ccccccc") ;
aSet.insert("ddddddd") ;
aSet.insert("e") ;
aSet.insert("f") ;
outputSet(aSet) ;
return 0 ;
}
该集合现在将使用仿函数MyStringLengthCompare
来订购其项目,因此,此代码将输出:
- e
- f
- aaaaa
- bbbbb
- ccccccc
- ddddddd
创建自己的订购功能时,必须遵循以下规则:
如果(lhs&lt; rhs)为真,则返回true,否则返回false
如果由于某种原因你的订购功能不尊重它,那么你的手上就会有一套破损。
答案 1 :(得分:5)
std::sort
重新排列您给出的序列元素。 set
中序列的排列是固定的,因此您可以拥有的唯一迭代器是const
迭代器。
您需要先将results
复制到vector
或deque
(或类似)。
vector sortable_results( results.begin(), results.end() );
答案 2 :(得分:3)
您可以通过提供自定义谓词来自定义set
中元素的顺序,以确定相对于现存成员的添加元素的顺序。 set
定义为
template <
class Key,
class Traits=less<Key>,
class Allocator=allocator<Key>
>
class set
Traits是
提供功能的类型 可以比较两个元素的对象 值作为排序键来确定它们 集合中的相对顺序。这个 参数是可选的,二进制 谓词少是默认值 值。
how to use lambda expression as a template parameter here上有背景信息。
在您的情况下,这转换为:
auto comp = [](const string& a, const string& b) -> bool
{ return a.length() < b.length(); };
auto results = std::set <string, decltype(comp)> (comp);
请注意,这将导致具有相同字符串长度的set
元素被视为重复项,这不是您想要的,只要我能理解所需的结果。
答案 3 :(得分:2)
sort需要set
未提供的随机访问迭代器(它是双向迭代器)。如果您更改代码以使用vector
,则编译正常。
答案 4 :(得分:1)
您无法对一组进行排序。它总是在键上排序(它们本身就是元素)。
更具体地说,std::sort
需要随机访问迭代器。 std::set
提供的迭代器不是随机的。
答案 5 :(得分:1)
由于我编写了您正在使用的原始代码,或许我可以扩展它...:)
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;
}
答案 6 :(得分:0)
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';
}
}
我使用了经典的排序/唯一/擦除组合来使结果集唯一。我还清理了你的代码,使其更加c ++ 0x-y。