我是C ++的新手。我的程序是一个问答游戏,用户可以选择问题的类别和级别。首先,我使用struct数据类型
struct QuestionInfo
{
string category;
string level;
string question;
string answer;
};
然后
vector<QuestionInfo> vec;
这部分的想法是将问题的信息包括(类别,级别,问题和答案)到每个元素。 然后在构建菜单和输出问题UI后,我转到过滤器
void category_filter()
{
for (unsigned int i = 0; i < vec.size(); i ++)
{
if (category_choice != vec[i].category)
vec.erase(vec.begin() + i );
}
}
Void level_filter()
{
for (unsigned int i = 0; i < vec.size(); i ++)
{
if (level_choice != vec[i].level)
vec.erase(vec.begin() + i );
}
}
因此,过滤器的想法是删除不包含匹配类别和级别的元素。但输出问题与我之前选择的类别和级别不匹配。我不确定我做错了什么。
答案 0 :(得分:2)
由于没有考虑擦除元素时发生的索引转换,您会被绊倒。我个人会依赖remove_if
和erase
与lambda来实现这一目标:
vec.erase(remove_if(begin(vec), end(vec), [&](const auto& i) { return category_choice != i.category; }, end(vec));
vec.erase(remove_if(begin(vec), end(vec), [&](const auto& i) { return level_choice != i.level; }, end(vec));
或者,您可以考虑将它们组合起来以提高速度:
vec.erase(remove_if(begin(vec), end(vec), [&](const auto& i) { return category_choice != i.category || level_choice != i.level; }, end(vec));
答案 1 :(得分:2)
让我用我的例子解释你的问题。假设您有一个10
元素的向量,有效索引是0
到9
个元素。你必须删除第5个元素i == 4
。你删除它,然后索引5
的第6个元素移动到索引为4
的第5个元素的位置。之后,您在i
中增加for
,它变为5
。因此,您跳过前面的第6个元素,现在是第5个元素,索引为4
。
您可以修改以下代码,将i ++
移至条件。
for (unsigned int i = 0; i < vec.size(); ) {
if (category_choice != vec[i].category)
vec.erase(vec.begin() + i );
else
i ++;
}
@Jonathan演示了C ++方式的首选解决方案。
答案 2 :(得分:1)
您可能想要remove_if + erase:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
int main()
{
struct QuestionInfo
{
std::string category;
std::string level;
std::string question;
std::string answer;
QuestionInfo(std::string category, std::string level, std::string question, std::string answer) :
category(category), level(level), question(question), answer(answer) {}
};
std::vector<QuestionInfo> vec;
std::string category_choice = "cat1";
std::string level_choice = "lev1";
vec.push_back(QuestionInfo("cat1", "lev1", "q1", "a1"));
vec.push_back(QuestionInfo("cat1", "lev2", "q2", "a2"));
vec.push_back(QuestionInfo("cat2", "lev1", "q3", "a3"));
vec.push_back(QuestionInfo("cat2", "lev2", "q4", "a4"));
std::cout << "\nNot filered" << std::endl;
for (auto const &info : vec)
std::cout << "Category:" << info.category << " Level:" << info.level << std::endl;
auto filter_category = std::remove_if(vec.begin(), vec.end(), [&](auto const &info) {return category_choice != info.category; });
vec.erase(filter_category, vec.end());
std::cout << "\nFilered by category" << std::endl;
for (auto const &info : vec)
std::cout << "Category:" << info.category << " Level:" << info.level << std::endl;
auto filter_level = std::remove_if(vec.begin(), vec.end(), [&](auto const &info) {return level_choice != info.level; });
vec.erase(filter_level, vec.end());
std::cout << "\nFiltered by level" << std::endl;
for (auto const &info : vec)
std::cout << "Category:" << info.category << " Level:" << info.level << std::endl;
system("pause");
return 0;
}
答案 3 :(得分:0)
正如其他人所说,remove_if
+ erase
是实现目标的标准和富有表现力的方式。但您也可以考虑使用copy_if
对新容器进行非破坏性过滤,甚至不使用Boost.Range适配器boost::adaptors::filtered
或boost::filter_iterator的任何其他存储。请查看here示例。