我从API接收Foo的向量,如下所示:
std::vector<Foo> foos;
然后我编写了一个名为
的函数std::vector<std::string> getKeys(const std::vector<Foo>&)
迭代容器并为每个Foo对象提取类型为std :: string的键。
如何以排序顺序迭代foos中的Foo对象,其中对键进行排序并以不区分大小写的方式进行排序。另外,我不想制作一个foos的分类副本,因为它的大小很大。
这是我的尝试,但是我想知道它是否可以做得更好。
struct CaseInsensitiveComparitor {
bool operator ()(const std::pair<std::string, Foo&> lhs, const std::pair<std::string, Foo&> rhs) const {
std::string str1 = lhs.first;
boost::algorithm::to_lower(str1);
std::string str2 = rhs.first;
boost::algorithm::to_lower(str2);
return (str1 < str2);
}
};
// map key to Foo
std::vector<std::pair<std::string, Foo*> > tempFoos;
{
std::vector<std::string> keys = getKeys(foos);
std::vector<std::string>::iterator begin = keys.begin();
std::vector<std::string>::iterator i = keys.begin();
std::vector<std::string>::iterator end = keys.end();
for(;i!=end;++i)
{
tempFoos.push_back(*i, &foos[distance(begin,i)]);
}
std::sort(tempFoos.begin(), tempFoos.end(), CaseInsensitiveComparitor());
}
std::vector<Foo*> sortedFoos;
std::vector<std::pair<std::string, Foo*> >::iterator i = tempFoos.begin();
std::vector<std::pair<std::string, Foo*> >::iterator end = tempFoos.end();
for(;i!=end;++i)
{
sortedFoos.push_back(i->second);
}
答案 0 :(得分:7)
除了你的尝试, 你可以创建一个索引数组
std::vector<size_t> indexes;
for (size_t i = 0; i != keys.size(); ++i) { indexes.push_back(i); }
使用比较器:
struct Comparator {
explicit Comparator(const std::vector<string>& keys) : keys(&keys) {}
bool operator ()(size_t lhs, size_t rhs) const {
std::string str1 = (*keys)[lhs];
boost::algorithm::to_lower(str1);
std::string str2 = (*keys)[rhs];
boost::algorithm::to_lower(str2);
return (str1 < str2);
}
private:
const std::vector<string>* keys;
};
对此索引数组进行排序
std::sort(indexes.begin(), indexes.end(), Comparator(keys));
现在,您可以使用索引间接迭代foos和/或键:
std::vector<Foo*> sortedFoos;
for (size_t i = 0; i != indexes.size(); ++i) {
sortedFoos.push_back(&foos[indexes[i]]);
}
答案 1 :(得分:3)
你关心的是当前迭代foos三次并将其排序一次。这将使您的算法在大型数组上的性能降低。为什么不改变它来执行以下操作
std::vecotr<Foo*>
std::sort(fooPtrVec.begin(), fooPtrVec.end(), YourNewComparisonFunction())
对Foo * 答案 2 :(得分:1)
for(;i!=end;++end)
你必须增加你的我而不是你的结局!
答案 3 :(得分:0)
您可以使用一组来为您排序密钥,并将它们封装在自定义容器中以获得更方便的可用性:
class Foo
{
public :
Foo(const std::string & key) : key(key) {}
const std::string & get_key() const { return key; }
private :
std::string key;
};
std::ostream & operator<<(std::ostream & stream, const Foo & foo) { stream << foo.get_key(); return stream; }
class SortedFoo
{
typedef std::set<std::pair<std::string,Foo*> > SortedFoos;
SortedFoos mFoos;
public :
SortedFoo(std::vector<Foo> & foos)
{
const std::vector<Foo>::iterator end = foos.end();
for(std::vector<Foo>::iterator iter = foos.begin(); iter != end; ++iter)
{
mFoos.insert(std::make_pair(boost::algorithm::to_lower_copy(iter->get_key()), &(*iter)));
}
}
class Iterator : public std::iterator<std::forward_iterator_tag, Foo>
{
private:
Iterator(SortedFoos::iterator iter) : mIter(iter) {}
SortedFoos::iterator mIter;
public :
Iterator & operator ++ () { ++mIter; return *this; }
bool operator != (const Iterator & other) const { return mIter != other.mIter; }
Foo & operator * () { return *mIter->second; }
Foo * operator -> () { return mIter->second; }
friend class SortedFoo;
};
typedef Iterator iterator;
iterator begin() { return Iterator(mFoos.begin()); }
iterator end() { return Iterator(mFoos.end()); }
};
int main(int argc, const char** argv)
{
std::vector<Foo> foos;
foos.push_back(Foo("def"));
foos.push_back(Foo("Jkl"));
foos.push_back(Foo("yz "));
foos.push_back(Foo("pqr"));
foos.push_back(Foo("Mno"));
foos.push_back(Foo("ghi"));
foos.push_back(Foo("vwx"));
foos.push_back(Foo("Abc"));
foos.push_back(Foo("stu"));
SortedFoo sorted(foos);
std::copy(sorted.begin(), sorted.end(), std::ostream_iterator<Foo>(std::cout, " "));
return 0;
}
如果您有重复的密钥,则无法使用集合。您可以通过仅进行少量修改的矢量替换它:
typedef std::vector<std::pair<std::string,Foo*> > SortedFoos;
//...
SortedFoo(std::vector<Foo> & foos)
{
const std::vector<Foo>::iterator end = foos.end();
for(std::vector<Foo>::iterator iter = foos.begin(); iter != end; ++iter)
{
mFoos.push_back(std::make_pair(boost::algorithm::to_lower_copy(iter->get_key()), &(*iter)));
}
std::sort(mFoos.begin(), mFoos.end());
}
//...