sort std::list case sensitive elements

#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 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.

Answers


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

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

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

yes

you can check the following code to use a custom comparator


Need Your Help

Is this a viable implementation of enums in Javascript?

javascript enums closures enumerable

I was interested in a really quick enumeration of constant values for a project I'm working on, but everything I found on StackOverflow was ridiculously over-complicated if all you want is to store

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.