如何使用struct数据类型删除向量中的特定元素

时间:2017-12-08 17:20:43

标签: c++ vector struct

我是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 );
   }
}

因此,过滤器的想法是删除不包含匹配类别和级别的元素。但输出问题与我之前选择的类别和级别不匹配。我不确定我做错了什么。

4 个答案:

答案 0 :(得分:2)

由于没有考虑擦除元素时发生的索引转换,您会被绊倒。我个人会依赖remove_iferase与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元素的向量,有效索引是09个元素。你必须删除第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;
}

enter image description here

答案 3 :(得分:0)

正如其他人所说,remove_if + erase是实现目标的标准和富有表现力的方式。但您也可以考虑使用copy_if对新容器进行非破坏性过滤,甚至不使用Boost.Range适配器boost::adaptors::filteredboost::filter_iterator的任何其他存储。请查看here示例。