0

我正在从 Foo 类型的数据库中读取一个对象,定义如下。该对象是 Foo 成员的向量,其中 Foo 成员由字符串 id 和容器对象组成。

typedef std::pair<std::string, Container> FooMember;
typedef std::vector<FooMember> Foo;

我希望以排序形式迭代 Foo 对象,其中排序是针对 id 完成的。为此,我使用以下函数首先创建对象的排序版本。如您所见,对象以不区分大小写的方式排序。与我目前的做法相比,我是否有更好的方法来迭代这个对象?

Foo sortedFoo(Foo& value) const {
    Foo returnValue;
    returnValue.reserve(value.size());

    // use a map to sort the items
    std::map<std::string, FooMember> sortedMembers;
    {
        Foo::iterator i = value.begin();
        Foo::iterator end = value.end();
        for(; i!=end; ++i) {
            std::string name = i->first;
            boost::algorithm::to_lower(name);
            sortedMembers[name] = *i;
        }
    }

    // convert the map to a vector of its values in sorted order
    std::map<std::string, FooMember >::iterator i = sortedMembers.begin();
    std::map<std::string, FooMember >::iterator end = sortedMembers.end();
    for(; i!=end; ++i) {
        returnValue.push_back(i->second);
    }
    return returnValue;
}
4

5 回答 5

4

是:复制向量,然后std::sort与自定义比较谓词一起使用:

struct ByIdCaseInsensitive {
  bool operator ()(const FooMember& lhs, const FooMember& rhs) const {
    return boost::algorithm::to_lower_copy(lhs.first) <
           boost::algorithm::to_lower_copy(rhs.first);
  }
};

比填充地图然后复制回矢量更有效。

如果谓词使用适当的 Unicode 排序算法,它会更好,但这在标准库或 Boost 中不可用。

于 2013-09-04T10:16:29.560 回答
1

最好的方法是使用std::sort自定义比较器FooMembers

bool cmp(const FooMember& lhs, const FooMember& rhs);

Foo sortedFoo(const Foo& value) const
{
  Foo tmp = value;
  return std::sort(tmp.begin(), tmp.end(), cmp);
}

可以在 和 的帮助下进行std::lexicographical_compare比较tolower

#include <cctype> // for std::tolower

bool ci_cmp(char a, char b)
{
  return std::tolower(a) < std::tolower(b);
}

#include <algorithm> // for std::sort, std::lexicographical_compare

bool cmp(const FooMember& lhs, const FooMember& rhs) 
{
  return std::lexicographical_compare(lhs.first.begin(),
                                      lhs.first.end(),
                                      rhs.first.begin(),
                                      rhs.first.end(),
                                      ci_cmp);
}
于 2013-09-04T10:16:30.910 回答
1

您可以使用std::sort

#include <algorithm>

bool comparator(const FooMember& i, const FooMember& j)
{
    std::string str1 = i.first;
    boost::algorithm::to_lower(str1);
    std::string str2 = j.first;
    boost::algorithm::to_lower(str2);
    return (str1 < str2); 
}

void sortFoo(Foo& value) {
    std::sort (value.begin(), value.end(), comparator);
}

或者,您可以从一开始就将Foo对象保留在 astd::map<std::string, Foo>中,以便它们始终保持排序。

于 2013-09-04T10:21:01.600 回答
-1

您还可以将 std::sort 与 lambda 表达式一起使用:

std::sort(value.begin(), value.end(), [](const FooMember &lhs, const FooMember &rhs)
{
    std::string str1 = i.first, str2 = j.first;
    boost::algorithm::to_lower(str1);
    boost::algorithm::to_lower(str2);
    return str1 < str2; 
});

或者使用erelender提供的版本。由你决定。

于 2013-09-04T10:38:28.747 回答
-3

语义std::vector<std::pair<T,U> >上是 a std::map<T,U>(但实现通常不同)。如果你可以重新设计Foo,你可能会更好。作为副作用,您将免费获得排序。

typedef std::map<std::string, Container> Foo;

于 2013-09-04T10:29:45.010 回答