如何使用区分大小写的元素对std :: list进行排序?

时间:2010-02-27 08:43:45

标签: c++ list sorting stl

这是我目前的代码:

#include <list>
#include <string>
using std::string;
using std::list;

int main()
{
    list <string> list_;
    list_.push_back("C");
    list_.push_back("a");
    list_.push_back("b");

    list_.sort();
}

sort()函数是否根据字符代码对元素进行排序?我希望在排序完成后,此处的结果为a b C

5 个答案:

答案 0 :(得分:8)

如果您想支持其他语言的字符,则不区分大小写的字符比较很棘手。这就是为什么以区域性合理的方式做这些的好主意:

struct char_iless 
: public std::binary_function<char, char, bool>
{
    std::locale loc;

    char_iless(std::locale const & loc=std::locale()) : loc(loc) 
    {
    }

    bool operator()(char a, char b) const
    {
        return std::tolower(a, loc) < std::tolower(b, loc);
    }
};

这是您使用此类比较两个字符的方式:

char_iless('a', 'b', my_locale);

如果您想使用设置为默认值的std::locale(),请使用my_locale

如果你可以使用Boost,那么String Algorithms库中就有is_iless仿函数,它可以做同样的事情。

由于std::lexicographical_compare

,将此字符从比较字符串扩展到字符串很容易
struct str_iless 
: public std::binary_function<std::string, std::string, bool>
{
    std::locale loc;

    str_iless(std::locale const & loc=std::locale()) : loc(loc) 
    {
    }

    bool operator()(std::string const & a, std::string const & b) const
    {
        return std::lexicographical_compare(
            a.begin(), a.end(),
            b.begin(), b.end(),  
            char_iless(loc)
        );
    }
};

现在您已经拥有解决问题所需的一切:

int main()
{
    std::list<std::string> list;
    list.push_back("C");
    list.push_back("a");
    list.push_back("b");

    // Sort using default locale
    list.sort(str_iless());  

    // Sort using French locale 
    // (warning: this locale format string is MS specific)
    std::locale loc("French_France.1252");
    list.sort(str_iless(loc));
}

答案 1 :(得分:4)

使用默认<的默认比较器(char_traits< char >)会将您的列表排序为C a b

请参阅list::sort

为了达到所需的顺序a b C,您可以:

  1. 使用custom char_traits
  2. 撰写string类型列表
  3. sort提供自定义字符串比较器的实例,例如

    bool istring_less(const string& lhs, const string& rhs) {
      string::const_iterator \
        lb = lhs.begin(), le = lhs.end(),
        rb = rhs.begin(), re = rhs.end();
      const char lc, rc;
      for ( ; lb != le && rb != re; ++lb, ++rb) {
        lc = tolower(*lb);
        rc = tolower(*rb);
        if (*lc < *rc) return true;
        if (*lc > *rc) return false;
      }
      // if rhs is longer than lhs then lhs<rhs
      return (rb != re);
    }
    ...
    list.sort(istring_less);
    

答案 2 :(得分:1)

以下是我认为更清洁,更快的选择:

#include    <string>
#include    <cstring>
#include    <iostream>
#include    <boost/algorithm/string.hpp>

using std::string;
using std::list;
using std::cout;
using std::endl;

using namespace boost::algorithm;

// recommended in Meyers, Effective STL when internationalization and embedded
// NULLs aren't an issue.  Much faster than the STL or Boost lex versions.
struct ciLessLibC : public std::binary_function<string, string, bool> {
    bool operator()(const string &lhs, const string &rhs) const {
        return strcasecmp(lhs.c_str(), rhs.c_str()) < 0 ? 1 : 0;
    }
};

// If you need sorting according to the default system local
struct ciLessBoost : std::binary_function<std::string, std::string, bool>
{
    bool operator() (const std::string & s1, const std::string & s2) const {
        return lexicographical_compare(s1, s2, is_iless());
    }
};

int main(void) {
    list <string> list_;
    list_.push_back("C");
    list_.push_back("a");
    list_.push_back("b");

    list_.sort(ciLessLibC());
    list_.sort(ciLessBoost());

    return 0;
}

答案 3 :(得分:0)

答案 4 :(得分:0)

C++11起,您也可以使用lambda expression代替定义比较器函数/结构:

#include <list>
#include <string>
#include <cstring>
#include <iostream>
using namespace std;

int main()
{
    list<string> list_;
    list_.emplace_back("C");
    list_.emplace_back("a");
    list_.emplace_back("b");

    list_.sort([](const string& a, const string& b) {
        return (strcasecmp(a.c_str(), b.c_str()) < 0);
    });

    for (auto const &str : list_)
        cout << str << endl;

    return 0;
}  

输出:

  

a
  b
  C

注意:函数strcasecmp()(在@ RobertS.Barnes的答案中也建议使用)不是C ++标准的,因此并非在每个系统上都可用。例如,如果您使用的是Visual Studio,则可以改用_stricmp()

如果国际化对您来说是一个问题,那么您可以像@Manuel在回答中那样使用语言环境。

Code on Ideone