сортировка — C ++ Печать карты в алфавитном порядке без учета регистра

У меня есть:

map<string, map<int,int>>

Есть ли способ напечатать содержимое этой карты в алфавитном порядке, но без учета регистра? Например, распечатайте его в следующем порядке:

A : 1:1, 2:2
a : 3:1
an : 2:1
And : 4:1
and : 3:1

В настоящее время я печатаю с использованием следующего:

for (auto it = tokens.begin(); it != tokens.end(); ++it){
cout << it->first << " : ";
auto const &internal_map = it->second;
for (auto it2 = internal_map.begin(); it2 != internal_map.end(); ++it2){
if (it2 != internal_map.begin())
cout << " , ";
cout << it2->first << ":" << it2->second;
}
cout << endl;
}

Это печатает все, однако сначала идет все заглавные буквы, а затем все строчные. Например:

A : 1:1, 2:2
And : 4:1
a : 3:1
an : 2:1
and : 3:1

3

Решение

Есть ли способ напечатать содержимое этой карты в алфавитном порядке, но без учета регистра?

Да.

  1. Вам нужно будет создать пользовательский функтор сравнения, который сравнивает две строки без учета регистра.

    struct cicompare
    {
    bool operator()(std::string const& lhsIn, std::string const& rhsIn) const
    {
    char const* lhs = lhsIn.c_str();
    char const* rhs = rhsIn.c_str();
    for ( ; *lhs != '\0' && *rhs != '\0'; ++lhs, ++rhs )
    {
    if ( tolower(*lhs) != tolower(*rhs) )
    {
    return ( tolower(*lhs) < tolower(*rhs) );
    }
    else if ( *lhs != *rhs)
    {
    if ( *(lhs+1) == '\0' && *(rhs+1) == '\0' )
    {
    return (*lhs < *rhs);
    }
    }
    }
    return (tolower(*lhs) < tolower(*rhs));
    }
    };
    
  2. Используйте функтор сравнения без учета регистра для создания карты.

    map<string, map<int,int>, cicompare> mymap;
    
  3. Если вы не хотите хранить упорядоченную карту без учета регистра, создайте копию исходной карты, используя cicompare как раз перед печатью и распечатайте новую карту.

    map<string, map<int,int>, cicompare> mapForPrinting;
    mapForPrinting.insert(originalMap.start(), originalMap.end());
    
3

Другие решения

Как указано в принятом ответе, вы хотите использовать map с пользовательской функцией сравнения. Хитрость заключается в правильном сравнении. Вы не хотите полностью нечувствительного к регистру сравнения, иначе «И» и «и» будут равны, и на карте будет только один из них. Ваши образцы данных не покрывают все случаи; например, какой будет порядок «An», «И», «AN», «И»? Следующая функция сравнения упорядочивает их «AN», «An», «AND», «And» — более короткие строки всегда меньше длинных строк с одинаковыми символами, и первый символ, который имеет другой регистр, — это прерыватель связей с верхним регистр перед строчными

struct CaseAwareCompare
{
bool operator()(const char * left, const char * right) const
{
bool tied = true, tiebreaker = false;
int i;
for (i = 0; left[i] != 0; ++i)
{
if (right[i] == 0)
return false;
if (tolower(left[i]) != tolower(right[i]))
return tolower(left[i]) < tolower(right[i]);
if (tied && left[i] != right[i])
{
tied = false;
tiebreaker = left[i] < right[i];
}
}
return (right[i] != 0) || (!tied && tiebreaker);
}

bool operator()(const string & left, const string & right) const
{
return operator()(left.c_str(), right.c_str());
}
};

Я боролся с тем, что назвать это; это не чувствительное к регистру сравнение, потому что оно различает входные данные с различным регистром. Я наконец решил, что это следует называть сравнением с учетом конкретного случая.

3

Вы можете хранить данные в векторе. Вы можете хранить данные как structure или же pair в векторе. Если вы используете pair затем,

vector< pair< string, map<int,int> > > needToSort;

Тогда вы можете позвонить std::sort в этом.

sort(needToSort.begin(), needToSort.end(), compareFunction);

compareFunction является,

bool compareFunction( pair< string, map<int,int> > firstElement, pair< string, map<int,int> > secondElement)
{
string firstString = firstElement.first;
string secondString = secondElement.first;
for(int i=0;i<firstString.size();i++)
firstString[i] = toLower(firstString [i]);

for(int i=0;i<secondString.size();i++)
secondString [i] = toLower(secondString[i]);

return firstString < secondString;
}

а затем вы можете распечатать вектор, который должен дать вам желаемый результат.

0

Я думаю, что обычный способ сделать это — создать индекс итераторов для отображаемых элементов:

// Return a range of iterators to the elements
// of the given range.
template <typename Range>
auto make_index(Range& range)
-> vector<decltype(range.begin())> {
vector<decltype(range.begin())> index;
for (auto i = begin(range), e = end(range); i != e; ++i) {
index.push_back(i);
}
return index;
}

и отсортировать итераторы в соответствии с критериями отображения:

auto index = make_index(tokens);
using iterator = decltype(tokens.begin());
sort(begin(index), end(index), [](iterator a, iterator b){
return boost::algorithm::ilexicographical_compare(a->first, b->first);
});

помня разыменовать итераторы для отображения:

cout << "Sorted:\n";
for (auto&& i : index) {
cout << i->first << ':';
for (auto const& j : i->second) {
cout << ' ' << j.first << ':' << j.second;
}
cout << '\n';
}

(Смотрите все это живут в Колиру).

Я использовал boost::algorithm::ilexicographical_compare, Повышение нечувствительного к регистру сравнения строк, зависящего от локали, чтобы сохранить некоторую типизацию.

0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector