我有一个:
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
答案 0 :(得分:3)
有没有办法按字母顺序打印此地图的内容,但不区分大小写?
是。
您必须创建一个自定义比较仿函数,以不区分大小写的方式比较两个字符串。
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));
}
};
使用不区分大小写的比较仿函数来创建地图。
map<string, map<int,int>, cicompare> mymap;
如果您不想以不区分大小写的方式存储地图,请在打印前使用cicompare
创建原始地图的副本并打印新地图。
map<string, map<int,int>, cicompare> mapForPrinting;
mapForPrinting.insert(originalMap.start(), originalMap.end());
答案 1 :(得分:3)
如接受的答案中所述,您希望使用带有自定义比较功能的map
。诀窍是进行适当的比较。您不希望完全不区分大小写,或者“和”和“和”相等,只允许其中一个在地图中。您的样本数据不包括所有案例;例如,“An”,“And”,“AN”,“AND”的顺序是什么?下面的比较函数命令它们为“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());
}
};
我为什么称之为挣扎;它不是一个不区分大小写的比较,因为它区分不同情况下的输入。我最终认为它应该被称为案例感知比较。
答案 2 :(得分:0)
您可以将数据存储在矢量中。您可以将数据存储为向量中的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;
}
然后你可以打印出能给你所需结果的矢量。
答案 3 :(得分: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
,Boost的不区分大小写的区域设置字符串比较,以节省一些输入。
答案 4 :(得分:0)
如果您想要一个自定义的“区分大小写”比较器(如proposed by Mark Ransom),它遵循Unicode的语言字母顺序(甚至是您自己的字母顺序实现),则可以使用std :: collate或boost :: collator。
struct CaseAwareCompare
{
operator()(const std::string& strLeft, const std::string& strRight) const
{
using namespace boost::locale;
std::locale loc;
// Quaternary level : consider all case, accents, and punctuation.
// The words must be identical in terms of Unicode representation.
if (-1 == use_facet<collator<char> >(loc).compare(collator_base::quaternary, strLeft.begin(),
strLeft.end(),
strRight.begin(),
strRight.end())) {
return true;
}
return false;
}
};
注意:根据您的应用程序,您可能需要使用collator_base ::相同的级别或使用规范化的Unicode字符串。
例如,使用两个不同的字符串(不匹配的代码点),但是使用相同的Unicode表示形式(显示给用户)。
“señor”:带有ñ。
“señor”:带有n + ◌̃。
没有规范化和使用collator_base :: quaternary ,这两个 字符串将在同一地图元素中。
没有规范化和使用collator_base :: identical ,这两个 字符串将位于不同的地图元素中,但是如果您显示 向用户映射元素,他不明白为什么会有两次 相同的字符串。
在您的应用程序中所有字符串标准化后,两个字符串 不会再有不同了,你可以 不用担心使用collator_base :: quaternary。