C++ 使用 find_first_not_of(char*) 删除向量元素
C++ Removing vector elements with find_first_not_of(char*)
我正在制作国际象棋游戏并尝试将有效位置添加到向量中。我正在处理的具体部分是马,我硬编码的一些位置不在棋盘上,具体取决于马在棋盘上的位置。我的坐标系对行使用 A-H,对列使用 0-8。
我已经定义了一个有效字符的字符数组(A-H 和 0-8),我正在使用 find_first_not_of 来识别和删除无效的坐标对。例如:
有效:A1
无效:?3 - 删除这个
问题:为什么我的函数删除了一些无效且不符合模式的坐标对,但没有删除其他坐标对?例如,使用位置 A2 作为输入、@4 和@0 已成功删除。然而,剩余的可用位置是 C3、C1、B4、?3、B0、?1。
如果输入是H2,那么F3、F1、G0、G4是可用的位置,J3、J1、I4、I0被成功移除,只给出有效位置的期望结果。
问题:我的输出有时是正确的,有时是错误的,因为使用相同的方法去除无效位置。
Parent class Piece.cpp:
char Piece::valids[16] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'0', '1', '2', '3', '4', '5', '6', '7'
};
void Piece::removeInvalids(vector<string>& v)
{
for (short i = 0; i < v.size(); i++)
{
string s = v.at(i);
size_t found = s.find_first_not_of(valids);
if (found != string::npos)
{
cout << v.at(i) << endl;
swap(v.at(i), v.back());
v.pop_back();
}
}
}
Child class Knight.h:
vector<string> getAvailPositions(Piece **all)
{
vector<string> v;
stringstream ss;
ss << static_cast<char>(position[0] + 2)
<< static_cast<char>(position[1] + 1);
v.push_back(ss.str());
stringstream ss2;
ss2 << static_cast<char>(position[0] + 2)
<< static_cast<char>(position[1] - 1);
v.push_back(ss2.str());
stringstream ss3;
ss3 << static_cast<char>(position[0] + 1)
<< static_cast<char>(position[1] + 2);
v.push_back(ss3.str());
stringstream ss4;
ss4 << static_cast<char>(position[0] - 1)
<< static_cast<char>(position[1] + 2);
v.push_back(ss4.str());
stringstream ss5;
ss5 << static_cast<char>(position[0] + 1)
<< static_cast<char>(position[1] - 2);
v.push_back(ss5.str());
stringstream ss6;
ss6 << static_cast<char>(position[0] - 1)
<< static_cast<char>(position[1] - 2);
v.push_back(ss6.str());
stringstream ss7;
ss7 << static_cast<char>(position[0] - 2)
<< static_cast<char>(position[1] - 1);
v.push_back(ss7.str());
stringstream ss8;
ss8 << static_cast<char>(position[0] - 2)
<< static_cast<char>(position[1] + 1);
v.push_back(ss8.str());
removeInvalids(v);
return v;
}
如果需要对此 post 进行任何更改以便更好地帮助我,请告诉我,谢谢。
您应该重新考虑您的设计——它既复杂又低效。这个怎么样:
typedef std::array<char, 2> Position;
vector<Position> Knight::getAvailPositions() const
{
vector<Position> v;
v.reserve(8);
for (char a : {2, -2}) {
for (char b : {1, -1}) {
v.emplace_back(position[0] + a, position[1] + b);
v.emplace_back(position[0] + b, position[1] + a);
}
}
removeInvalids(v);
return v;
}
bool invalid(Position p)
{
return p[0] < 'A' || p[0] > 'H' || p[1] < '0' || p[1] > '7';
}
void Piece::removeInvalids(vector<Position>& v)
{
v.erase(std::remove_if(v.begin(), v.end(), invalid), v.end());
}
这避免了隐藏在所有这些字符串和字符串流中的大量动态内存分配。现在您每个 getAvailPositions()
电话只有一个。而且代码更少。
它有时只是正确的原因是因为您将当前矢量元素与最后的元素交换,然后移动到下一个元素。如果向量末尾的元素无效,您只是将无效元素滑入向量中间并跳过它。
在您的示例中,当它删除 @4 时,它会将 ?3 拉到向量的中间,然后继续查看 b0,甚至不询问 ?3。如果您想继续按照现在的方式使用代码,您将需要修改从向量中间删除元素的逻辑。
不过,正如其他答案所指出的,还有更有效的方法来编写此代码。
D.R 你对我的代码是正确的,这似乎通过添加这一行来解决问题:
void Piece::removeInvalids(vector<string>& v)
{
for (short i = 0; i < v.size(); i++)
{
string s = v.at(i);
size_t found = s.find_first_not_of(valids);
if (found != string::npos)
{
cout << v.at(i) << endl;
swap(v.at(i), v.back());
v.pop_back();
i = 0;
}
}
}
让它重新开始循环。我打算暂时保持这种方式,因为我必须在 6 月 2 日之前完成这个项目并记录下来,哈哈。我相信我的老师会作为学习经验向 class 解释它有多糟糕,但我们还没有深入讨论性能,这将是我下一门 C++ 课程的重点。我拿CSC-17C调性能的时候可以修改这个程序
感谢大家的快速回复!
我正在制作国际象棋游戏并尝试将有效位置添加到向量中。我正在处理的具体部分是马,我硬编码的一些位置不在棋盘上,具体取决于马在棋盘上的位置。我的坐标系对行使用 A-H,对列使用 0-8。
我已经定义了一个有效字符的字符数组(A-H 和 0-8),我正在使用 find_first_not_of 来识别和删除无效的坐标对。例如:
有效:A1
无效:?3 - 删除这个
问题:为什么我的函数删除了一些无效且不符合模式的坐标对,但没有删除其他坐标对?例如,使用位置 A2 作为输入、@4 和@0 已成功删除。然而,剩余的可用位置是 C3、C1、B4、?3、B0、?1。
如果输入是H2,那么F3、F1、G0、G4是可用的位置,J3、J1、I4、I0被成功移除,只给出有效位置的期望结果。
问题:我的输出有时是正确的,有时是错误的,因为使用相同的方法去除无效位置。
Parent class Piece.cpp:
char Piece::valids[16] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'0', '1', '2', '3', '4', '5', '6', '7'
};
void Piece::removeInvalids(vector<string>& v)
{
for (short i = 0; i < v.size(); i++)
{
string s = v.at(i);
size_t found = s.find_first_not_of(valids);
if (found != string::npos)
{
cout << v.at(i) << endl;
swap(v.at(i), v.back());
v.pop_back();
}
}
}
Child class Knight.h:
vector<string> getAvailPositions(Piece **all)
{
vector<string> v;
stringstream ss;
ss << static_cast<char>(position[0] + 2)
<< static_cast<char>(position[1] + 1);
v.push_back(ss.str());
stringstream ss2;
ss2 << static_cast<char>(position[0] + 2)
<< static_cast<char>(position[1] - 1);
v.push_back(ss2.str());
stringstream ss3;
ss3 << static_cast<char>(position[0] + 1)
<< static_cast<char>(position[1] + 2);
v.push_back(ss3.str());
stringstream ss4;
ss4 << static_cast<char>(position[0] - 1)
<< static_cast<char>(position[1] + 2);
v.push_back(ss4.str());
stringstream ss5;
ss5 << static_cast<char>(position[0] + 1)
<< static_cast<char>(position[1] - 2);
v.push_back(ss5.str());
stringstream ss6;
ss6 << static_cast<char>(position[0] - 1)
<< static_cast<char>(position[1] - 2);
v.push_back(ss6.str());
stringstream ss7;
ss7 << static_cast<char>(position[0] - 2)
<< static_cast<char>(position[1] - 1);
v.push_back(ss7.str());
stringstream ss8;
ss8 << static_cast<char>(position[0] - 2)
<< static_cast<char>(position[1] + 1);
v.push_back(ss8.str());
removeInvalids(v);
return v;
}
如果需要对此 post 进行任何更改以便更好地帮助我,请告诉我,谢谢。
您应该重新考虑您的设计——它既复杂又低效。这个怎么样:
typedef std::array<char, 2> Position;
vector<Position> Knight::getAvailPositions() const
{
vector<Position> v;
v.reserve(8);
for (char a : {2, -2}) {
for (char b : {1, -1}) {
v.emplace_back(position[0] + a, position[1] + b);
v.emplace_back(position[0] + b, position[1] + a);
}
}
removeInvalids(v);
return v;
}
bool invalid(Position p)
{
return p[0] < 'A' || p[0] > 'H' || p[1] < '0' || p[1] > '7';
}
void Piece::removeInvalids(vector<Position>& v)
{
v.erase(std::remove_if(v.begin(), v.end(), invalid), v.end());
}
这避免了隐藏在所有这些字符串和字符串流中的大量动态内存分配。现在您每个 getAvailPositions()
电话只有一个。而且代码更少。
它有时只是正确的原因是因为您将当前矢量元素与最后的元素交换,然后移动到下一个元素。如果向量末尾的元素无效,您只是将无效元素滑入向量中间并跳过它。
在您的示例中,当它删除 @4 时,它会将 ?3 拉到向量的中间,然后继续查看 b0,甚至不询问 ?3。如果您想继续按照现在的方式使用代码,您将需要修改从向量中间删除元素的逻辑。
不过,正如其他答案所指出的,还有更有效的方法来编写此代码。
D.R 你对我的代码是正确的,这似乎通过添加这一行来解决问题:
void Piece::removeInvalids(vector<string>& v)
{
for (short i = 0; i < v.size(); i++)
{
string s = v.at(i);
size_t found = s.find_first_not_of(valids);
if (found != string::npos)
{
cout << v.at(i) << endl;
swap(v.at(i), v.back());
v.pop_back();
i = 0;
}
}
}
让它重新开始循环。我打算暂时保持这种方式,因为我必须在 6 月 2 日之前完成这个项目并记录下来,哈哈。我相信我的老师会作为学习经验向 class 解释它有多糟糕,但我们还没有深入讨论性能,这将是我下一门 C++ 课程的重点。我拿CSC-17C调性能的时候可以修改这个程序
感谢大家的快速回复!