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

发布于 2024-08-23 07:46:56 字数 353 浏览 1 评论 0 原文

这是我当前的代码:

#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() 函数是否根据元素的字符代码对元素进行排序?我希望排序完成后这里的结果是 ab C

This is my current code:

#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();
}

Does the sort() function sort the elements according to their character codes? I want the result here to be a b C after the sorting is done.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

养猫人 2024-08-30 07:46:56

如果您想支持其他语言的字符,则不区分大小写的字符比较会很棘手。这就是为什么以区域设置敏感的方式执行它们是一个好主意:

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 code> 如果您想使用默认设置的代码。

如果你可以使用 Boost,那么字符串算法库中有一个 is_iless 函子可以做同样的事情。

借助 std::lexicographyal_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));
}

Case-insensitive character comparisons are tricky if you want to support characters from other languages. That's why it's a good idea to do them in a locale-sensible manner:

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);
    }
};

This is how you use this class to compare two chars:

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

Just use std::locale() as my_locale if you want to use the one that's set as default.

If you can use Boost then there is am is_iless functor in the String Algorithms library which does the same thing.

Extending this from comparing chars to strings is easy thanks to 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)
        );
    }
};

Now you have all that it's required to solve your problem:

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));
}
回眸一遍 2024-08-30 07:46:56

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

请参阅list::sort

为了达到所需的顺序 ab C 您可以:

  1. 使用 自定义 char_traits
  2. 提供自定义字符串比较器的实例排序,例如

    bool istring_less(const string& lhs, const string& rhs) {
      字符串::const_iterator \
        lb = lhs.begin(), le = lhs.end(),
        rb = rhs.begin(), re = rhs.end();
      常量字符 lc、rc;
      for (; lb != le && rb != re; ++lb, ++rb) {
        lc = tolower(*lb);
        rc = tolower(*rb);
        if (*lc < *rc) 返回 true;
        if (*lc > *rc) 返回 false;
      }
      // 如果 rhs 比 lhs 长,则 lhs

The default comparator (<) using the default char_traits< char > will sort your list as C a b.

See list::sort.

In order to achieve the desired order a b C you can either:

  1. compose your list of string types with custom char_traits, or
  2. provide an instance of a custom string comparator to sort, e.g.

    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);
    
千里故人稀 2024-08-30 07:46:56

以下是我认为更干净、速度更快的替代方案:

#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;
}

Here are what I consider to be some cleaner and one significantly faster alternative:

#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;
}
捶死心动 2024-08-30 07:46:56

C++11 开始,您还可以使用 lambda 表达式 而不是定义比较器函数/结构:

#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;
}  

输出:

一个
b

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

如果国际化对您来说是一个问题,那么您可以像 @Manuel 在他的回答中所做的那样应用区域设置。

Ideone 上的代码

Since C++11, you can also use a lambda expression instead of defining a comparator function/struct:

#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;
}  

Output:

a
b
C

Note: The function strcasecmp() (as also suggested in the answer by @RobertS.Barnes) is not in the C++ standard and, therefore, not available on every system. For example, if you are using Visual Studio, you could use _stricmp() instead.

If internationalization is an issue for you, then you can apply a locale as @Manuel did in his answer.

Code on Ideone

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文