C++ std::set<string> 字母数字自定义比较器
C++ std::set<string> Alphanumeric custom comparator
我正在使用字符串数组的排序非冗余排列解决问题。
例如,如果输入字符串是"8aC"
,那么输出应该是{"Ca8","C8a", "aC8", "a8C", "8Ca", "9aC"}
这样的顺序。我选择C++数据结构集合是因为每次我将字符串插入std:set时,集合会自动排序并且消除冗余。输出很好。
但我想按不同的字母数字顺序对集合进行排序,这与默认的字母数字排序顺序不同。我想自定义设置顺序优先级的比较器,如:upper case> lower case > digit
。
我尝试自定义比较器,但非常令人沮丧。 如何自定义集合的排序顺序?这是我的代码。
set<string, StringCompare> setl;
for (i = 0; i < f; i++)
{
setl.insert(p[i]); //p is String Array. it has the information of permutation of String.
}
for (set<string>::iterator iter = setl.begin(); iter != setl.end(); ++iter)
cout << *iter << endl; //printing set items. it works fine.
struct StringCompare
{
bool operator () (const std::string s_left, const std::string s_right)
{
/*I want to use my character comparison function in here, but have no idea about that.
I'm not sure about that this is the right way to customize comparator either.*/
}
};
int compare_char(const char x, const char y)
{
if (char_type(x) == char_type(y))
{
return ( (int) x < (int) y) ? 1 : 0 ;
}
else return (char_type(x) > char_type(y)) ? 1 : 0;
}
int char_type(const char x)
{
int ascii = (int)x;
if (ascii >= 48 && ascii <= 57) // digit
{
return 1;
}
else if (ascii >= 97 && ascii <= 122) // lowercase
{
return 2;
}
else if (ascii >= 48 && ascii <= 57) // uppercase
{
return 3;
}
else
{
return 0;
}
}
你的比较是对的。我会像这样将参数转换为 const ref
bool operator () (const std::string &s_left, const std::string &s_right)
并从这个简单的实现开始:
return s_left < s_right
这将提供默认行为,让您确信自己走在正确的轨道上。
然后开始在两个字符串的长度之间的较短的时间上使用 for 循环比较一个字符。您可以简单地使用 operator[](例如 s_left[i])
从字符串中获取字符
你已经很接近你所拥有的了。
在你的比较仿函数中,你有两个 std::string
。您需要做的是找到两个字符串不同的第一个位置。为此,您可以使用标准库中的 std::mismatch
。这个 returns 一个 std::pair
填充了指向不同的前两个元素的迭代器:
auto iterators = std::mismatch(std::begin(s_left), std::end(s_left),
std::begin(s_right), std::end(s_right));
现在,您可以取消引用我们为获取字符而提供的两个迭代器:
char c_left = *iterators.first;
char c_right = *iterators.second;
您可以将这两个字符传递给您的 compare_char
函数,它应该都能正常工作:-)
对此不是绝对确定,但您可以使用枚举 class 来发挥您的优势或使用数组,并选择以您喜欢的顺序从某些索引中读取。
你可以用一个枚举class来定义你想要输出数据的顺序,另一个包含要输出的数据,然后你可以设置一个循环,一直循环赋值以置换的方式输出!
namespace CustomeType
{
enum Outs { Ca8= 0,C8a, aC8, a8C, 8Ca, 9aC };
enum Order{1 = 0 , 2, 3 , 4 , 5};
void PlayCard(Outs input)
{
if (input == Ca8) // Enumerator is visible without qualification
{
string[] permuted;
permuted[0] = Outs[0];
permuted[1] = Outs[1];
permuted[2] = Outs[2];
permuted[3] = Outs[3];
permuted[4] = Outs[4];
}// else use a different order
else if (input == Ca8) // this might be much better
{
string[] permuted;
for(int i = 0; i<LessThanOutputLength; i++)
{
//use order 1 to assign values from Outs
}
}
}
}
这应该有效:
bool operator () (const std::string s_left, const std::string s_right)
{
for(int i = 0;i < s_left.size();i++){
if(isupper(s_left[i])){
if(isupper(s_right[i])) return s_left[i] < s_right[i];
else if(islower(s_right[i]) || isdigit(s_right[i]))return true;
}
else if(islower(s_left[i])){
if(islower(s_right[i])) return s_left[i] < s_right[i];
else if(isdigit(s_right[i])) return true;
else if(isupper(s_right[i])) return false;
}
else if(isdigit(s_left[i])){
if(isdigit(s_right[i])) return s_left[i] < s_right[i];
else if(islower(s_right[i]) || isupper(s_right[i])) return false;
}
}
}
你快到了,但你应该按字典顺序比较你的字符串。
我对您的代码进行了粗略的小改动。
int char_type( const char x )
{
if ( isupper( x ) )
{
// upper case has the highest priority
return 0;
}
if ( islower( x ) )
{
return 1;
}
if ( isdigit( x ) )
{
// digit has the lowest priority
return 2;
}
// something else
return 3;
}
bool compare_char( const char x, const char y )
{
if ( char_type( x ) == char_type( y ) )
{
// same type so that we are going to compare characters
return ( x < y );
}
else
{
// different types
return char_type( x ) < char_type( y );
}
}
struct StringCompare
{
bool operator () ( const std::string& s_left, const std::string& s_right )
{
std::string::const_iterator iteLeft = s_left.begin();
std::string::const_iterator iteRight = s_right.begin();
// we are going to compare each character in strings
while ( iteLeft != s_left.end() && iteRight != s_right.end() )
{
if ( compare_char( *iteLeft, *iteRight ) )
{
return true;
}
if ( compare_char( *iteRight, *iteLeft ) )
{
return false;
}
++iteLeft;
++iteRight;
}
// either of strings reached the end.
if ( s_left.length() < s_right.length() )
{
return true;
}
// otherwise.
return false;
}
};
我正在使用字符串数组的排序非冗余排列解决问题。
例如,如果输入字符串是"8aC"
,那么输出应该是{"Ca8","C8a", "aC8", "a8C", "8Ca", "9aC"}
这样的顺序。我选择C++数据结构集合是因为每次我将字符串插入std:set时,集合会自动排序并且消除冗余。输出很好。
但我想按不同的字母数字顺序对集合进行排序,这与默认的字母数字排序顺序不同。我想自定义设置顺序优先级的比较器,如:upper case> lower case > digit
。
我尝试自定义比较器,但非常令人沮丧。 如何自定义集合的排序顺序?这是我的代码。
set<string, StringCompare> setl;
for (i = 0; i < f; i++)
{
setl.insert(p[i]); //p is String Array. it has the information of permutation of String.
}
for (set<string>::iterator iter = setl.begin(); iter != setl.end(); ++iter)
cout << *iter << endl; //printing set items. it works fine.
struct StringCompare
{
bool operator () (const std::string s_left, const std::string s_right)
{
/*I want to use my character comparison function in here, but have no idea about that.
I'm not sure about that this is the right way to customize comparator either.*/
}
};
int compare_char(const char x, const char y)
{
if (char_type(x) == char_type(y))
{
return ( (int) x < (int) y) ? 1 : 0 ;
}
else return (char_type(x) > char_type(y)) ? 1 : 0;
}
int char_type(const char x)
{
int ascii = (int)x;
if (ascii >= 48 && ascii <= 57) // digit
{
return 1;
}
else if (ascii >= 97 && ascii <= 122) // lowercase
{
return 2;
}
else if (ascii >= 48 && ascii <= 57) // uppercase
{
return 3;
}
else
{
return 0;
}
}
你的比较是对的。我会像这样将参数转换为 const ref
bool operator () (const std::string &s_left, const std::string &s_right)
并从这个简单的实现开始:
return s_left < s_right
这将提供默认行为,让您确信自己走在正确的轨道上。 然后开始在两个字符串的长度之间的较短的时间上使用 for 循环比较一个字符。您可以简单地使用 operator[](例如 s_left[i])
从字符串中获取字符你已经很接近你所拥有的了。
在你的比较仿函数中,你有两个 std::string
。您需要做的是找到两个字符串不同的第一个位置。为此,您可以使用标准库中的 std::mismatch
。这个 returns 一个 std::pair
填充了指向不同的前两个元素的迭代器:
auto iterators = std::mismatch(std::begin(s_left), std::end(s_left),
std::begin(s_right), std::end(s_right));
现在,您可以取消引用我们为获取字符而提供的两个迭代器:
char c_left = *iterators.first;
char c_right = *iterators.second;
您可以将这两个字符传递给您的 compare_char
函数,它应该都能正常工作:-)
对此不是绝对确定,但您可以使用枚举 class 来发挥您的优势或使用数组,并选择以您喜欢的顺序从某些索引中读取。
你可以用一个枚举class来定义你想要输出数据的顺序,另一个包含要输出的数据,然后你可以设置一个循环,一直循环赋值以置换的方式输出!
namespace CustomeType
{
enum Outs { Ca8= 0,C8a, aC8, a8C, 8Ca, 9aC };
enum Order{1 = 0 , 2, 3 , 4 , 5};
void PlayCard(Outs input)
{
if (input == Ca8) // Enumerator is visible without qualification
{
string[] permuted;
permuted[0] = Outs[0];
permuted[1] = Outs[1];
permuted[2] = Outs[2];
permuted[3] = Outs[3];
permuted[4] = Outs[4];
}// else use a different order
else if (input == Ca8) // this might be much better
{
string[] permuted;
for(int i = 0; i<LessThanOutputLength; i++)
{
//use order 1 to assign values from Outs
}
}
}
}
这应该有效:
bool operator () (const std::string s_left, const std::string s_right)
{
for(int i = 0;i < s_left.size();i++){
if(isupper(s_left[i])){
if(isupper(s_right[i])) return s_left[i] < s_right[i];
else if(islower(s_right[i]) || isdigit(s_right[i]))return true;
}
else if(islower(s_left[i])){
if(islower(s_right[i])) return s_left[i] < s_right[i];
else if(isdigit(s_right[i])) return true;
else if(isupper(s_right[i])) return false;
}
else if(isdigit(s_left[i])){
if(isdigit(s_right[i])) return s_left[i] < s_right[i];
else if(islower(s_right[i]) || isupper(s_right[i])) return false;
}
}
}
你快到了,但你应该按字典顺序比较你的字符串。 我对您的代码进行了粗略的小改动。
int char_type( const char x )
{
if ( isupper( x ) )
{
// upper case has the highest priority
return 0;
}
if ( islower( x ) )
{
return 1;
}
if ( isdigit( x ) )
{
// digit has the lowest priority
return 2;
}
// something else
return 3;
}
bool compare_char( const char x, const char y )
{
if ( char_type( x ) == char_type( y ) )
{
// same type so that we are going to compare characters
return ( x < y );
}
else
{
// different types
return char_type( x ) < char_type( y );
}
}
struct StringCompare
{
bool operator () ( const std::string& s_left, const std::string& s_right )
{
std::string::const_iterator iteLeft = s_left.begin();
std::string::const_iterator iteRight = s_right.begin();
// we are going to compare each character in strings
while ( iteLeft != s_left.end() && iteRight != s_right.end() )
{
if ( compare_char( *iteLeft, *iteRight ) )
{
return true;
}
if ( compare_char( *iteRight, *iteLeft ) )
{
return false;
}
++iteLeft;
++iteRight;
}
// either of strings reached the end.
if ( s_left.length() < s_right.length() )
{
return true;
}
// otherwise.
return false;
}
};