我在自定义排序字符串方面遇到了一些问题。我基本上拥有std::list
std::pair
,其元素为enum class
和std::string
。 Enum 用于颜色(正确排序)和字符串包含[2,10]间隔中的数字,分别添加字母J,Q,K和A.正如您可能已经猜到的那样,它是一副卡片,在排序后必须看起来像这样:
2,3,4,5,6,7,8,9,10,J,Q,K,A。
为了达到这个目的,我的lambda函数应该是什么样的?或者还有另一种方式吗?
到目前为止,这是我的竞争对手:
enum class Colours
{
Spades, Clubs, Hearts, Diamonds
};
typedef std::list<std::pair<Colours, std::string>> Deck;
typedef std::pair<Boje, std::string> Pair;
这是实际的排序:
deck.sort( [] (const Pair &x, const Pair &y) -> bool {
if(x.first == y.first) return x.second < y.second;
else return x.first < y.first;
} );
目前的排序结果:10 2 3 4 5 6 7 8 9 A J K Q
答案 0 :(得分:3)
你要做的一件事是每个string
的第一个字符是唯一的。此代码未经测试,但应该接近:
unsigned int face_value(std::string const &face) {
if(std::isdigit(face[0])) {
// if the length is 1 we just need the digit
if(face.length() == 1) {
return face[0] - '0';
}
// if it's not 1, it has to be 10
return 10;
}
switch(face[0]) {
case 'J':
return 11;
break;
case 'Q':
return 12;
break;
case 'K':
return 13;
break;
case 'A':
return 14;
break;
default:
assert(false);
break;
}
}
bool face_compare(std::string const &first, std::string const &second) {
return face_value(first) < face_value(second);
}
使用辅助函数,lambda是微不足道的:
deck.sort( [] (const Pair &x, const Pair &y) -> bool {
return std::tie(x.first, face_value(x.second)) <
std::tie(y.first, face_value(y.second));
});
作为旁注,我的猜测是你想在Colour
之前比较面值,但我现在仍然坚持原始逻辑。
答案 1 :(得分:3)
您可以查看卡片的面值,表示为std::map<std::string, int>
。我们可以使用std::tuple
小于std::tie
,而不是明确指定少于两个值。
// throws std::out_of_range if not passed a valid face
int face_value (const std::string & face)
{
static const std::map<std::string, int> faces {
{ "2", 2 }, { "3", 3 }, { "4", 4 },
{ "5", 5 }, { "6", 6 }, { "7", 7 },
{ "8", 8 }, { "9", 9 }, { "10", 10 },
{ "J", 11 }, { "Q", 12 }, { "K", 13 },
{ "A", 14 },
}
return faces.at( face );
}
deck.sort( [] (const Pair &x, const Pair &y) -> bool {
return std::tie(x.first, face_value(x.second)) < std::tie(y.first, face_value(y.second));
} );
答案 2 :(得分:0)
由于10
小于2
,因此1
小于2
,因此不会按照您想要的方式进行排序。使用类和比较运算符可能会更好:
struct Card {
enum class Suite { Spades, Clubs, Hearts, Diamonds};
operator<(const Card& other) {
if (suite == other.suite) { return number < other.number; }
return suite < other.suite;
}
string toString(); // Function to make your card string representation.
private:
int number; // 2 - 14 (11, 12, 13, 14: J, Q, K, A)
Suite suite;
}
然后你可以这样做:
std::list<Card> myList;
myList.sort();
注意:未经测试的代码,也需要适当的构造函数转换器等。
答案 3 :(得分:0)
问题在于您要比较string
s,即按字母顺序比较它们。让我们看看哪些比较会产生不好的结果:
2,3,4,5,6,7,8,9与10
J vs A
Q vs K
K vs A
因此,您需要编写比较以检查是否有任何值为10,A或J.如果是10,请检查另一个是否为数字。如果是A,检查另一个是J还是K.如果是K,检查另一个是Q还是A.如果满足任何一种情况,则返回符合您需要的逻辑值。否则像以前一样工作:
deck.sort( [] (const Pair &x, const Pair &y) -> bool {
if(x.first == y.first) {
//Here you need to implement your custom cases as described above
return x.second < y.second;
}
else return x.first < y.first;
} );
答案 4 :(得分:0)
关于诉讼和价值的枚举如何:
enum class Suit {
Spades, Clubs, Hearts, Diamonds
};
enum class Val {
v2, v3, v4, v5, v6, v7, v8, v9, v10, vJ, vQ, vK, vA
};
typedef std::pair<Suit, Val> Pair;
然后,如果你想要它,打印Pair
:
std::string GetCardName(Pair p)
{
std::string suit_name;
switch (p.first)
{
case Suit::Spades : suit_name = "Spades"; break;
/* ... */
case Suit::Diamonds : suit_name = "Diamonds"; break;
}
std::string val_name;
switch (p.second)
{
case Val::v2 : val_name = "2"; break;
case Val::v3 : val_name = "3"; break;
/* ... */
case Val::vA : val_name = "Ace"; break;
}
return val_name + " of " + suit_name;
}
然后你可以完全按照你最初的写作进行比较,因为Suit和Val枚举是隐式排序的:
std::list<Pair> Deck =
{
std::make_pair(Suit::Spades, Val::vA),
std::make_pair(Suit::Clubs, Val::v7)
};
Deck.sort( [](const Pair& p1, const Pair& p2)
{
if(p1.first == p2.first) return p1.second < p2.second;
else return p1.first < p2.first;
} );
for (const auto& pair : Deck)
{
std::cout << GetCardName(pair) << std::endl;
}
输出:
Ace of Spades
7 of Clubs
这是整个事情的minimal working example。