在向量对中通过索引删除元素

4

我有一组整数向量,第一个和第二个位置上都有整数,输入是相当特定的。
首先,我有i个输入,它们全部进入向量的第一个位置,但是之后会来到第二个输入数组,这个数组应该放在第二个位置。
然而,我想要做的是,如果我发现第二个位置的输入大于某个值(mana,在我的情况下是变量),我希望不把它放到向量对中,并从第一个位置中删除该索引处的第一个元素,我遇到了编写代码的困难。 这是代码的一部分:

vector<pair<int, int>>spellOne;

for (int i = 0; i < nSpellOne; i++)
{
    scanf_s("%d", &input);
    spellOne.back().first = input;
}

for (int i = 0; i < nSpellOne; i++)
{
    scanf_s("%d", &input);

    if (input > mana)
    {
        // removing the element on .first position at i index
    }
    else
    {
        spellOne.at(i).second = input;
    }
}

有没有人能帮我解决如何做到这一点以及是否可能,或者我应该切换到不同类型的数组?我也考虑使用映射,但是这不可能,因为在向量的第一个/第二个位置上我很有可能得到相同的值,因此我不能使用它们作为键。


你需要删除索引为i的整个对,但是还要将i减1(注意不要使i变成负数) - gsamaras
我尝试使用向量的erase函数来完成这个任务,但是我遇到了一个错误,需要指定第一个或第二个位置。当我构建程序并使用spellOne.erase(spellOne.begin() + i)来删除元素时,程序会崩溃,并显示“vector iterator offset out of range”的错误提示。 - saras
没错,Sara,看看我发布的答案示例,应该足以帮助你提升!;) - gsamaras
2个回答

4
我做了一个例子,可以帮助你完成任务。在下面的例子中,我填充了向量,然后删除了第二个值大于某个阈值(在本例中为2)的对。
现在,您可以使用两个变量来跟踪循环删除元素,一个用于遍历整个向量,另一个用于跟踪要检查的当前索引;如果我们删除了 v[3],那么下一个元素 v[4] 就会被移动(因为我们调用了 erase()),代替了 v[3],因此我们应该再次检查索引 3!
#include <iostream>
#include <utility>
#include <vector>

using namespace std;


int main()
{
    vector< pair<int, int> > v;
    int N = 5;
    const int threshold = 2;
    for(int i = 0; i < N; ++i)
        v.push_back(make_pair(i, i));

    int i = 0;
    while(i < v.size())
        if (v[i].second > threshold)
            v.erase(v.begin() + i);
        else
            i++;

    for(int i = 0; i < v.size(); ++i)
        cout << "(" << v[i].first << ", " << v[i].second << ")\n";

    cout << "Done" << endl;
}

输出:

(0, 0)
(1, 1)
(2, 2)
Done

针对您的评论进行编辑:您可以尝试以下方法:

int i = 0;
while(i < nSpellOne.size())
{
    scanf_s("%d", &input);
    if (input > mana)
        nSpellOne.erase(nSpellOne.begin() + i);
    else
        i++;
}

提示 - 在编写高效代码时,不要担心 std::cinscanf() 哪个更快,而是要专注于你的算法!


啊,我暗自希望有一种有效的解决方案可以立即删除元素,但这比我之前的方法更好,只需循环遍历整个内容。非常感谢! :) - saras
@Sara 当输入到达时,如果满足条件,您不知道需要删除哪个对,因此必须循环遍历向量或调用std::find(),这可能与我的解决方案一样有效。感谢您提出的好问题!=) - gsamaras
我想我只是认为i可以作为查找元素的方式,因为第一组输入与第二组输入的长度相同,因此它们应该在相同的位置,但我忽略了erase()会向后移动元素的事实。 - saras

1
首先,你加载向量的代码并不完全正确。
vector<pair<int, int>>spellOne;

for (int i = 0; i < nSpellOne; i++)
{
    int input1, input2;
    //scanf is C! Prefer C++ for doing input
    if(std::cin >> input1 >> input2)
        //Simply calling .back() presumes that an element already exists there, which in
        //the code you've provided, this isn't the case. emplace_back will allocate the 
        //memory correctly.
        spellOne.emplace_back(input1, input2);
    else
        break;//Could also do error handling here
}
并不会神奇地为您查询的任何元素腾出空间:您必须明确使用将元素插入向量的方法,无论是emplace_back(理想),emplace、push_back还是insert。back只请求最后一个元素,并且如果所要求的元素不存在或者您希望每次调用返回一个唯一元素,则会产生错误结果。

然后,在迭代向量时,正确使用STL将极大简化事情。

auto it = std::remove_if(
    spellOne.begin(),
    spellOne.end(),
    [mana](std::pair<int, int> const& data) {
        if(data.second > mana) return true;
        else return false;
    }
);

spellOne.erase(it, spellOne.end());

这段代码对您的用例进行了小改动,我们同时提供第二个数字和第一个数字作为程序的输入,所以该程序的输入将是1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10。如果您确实需要之前的顺序(尽管我不建议这样做),那么这段代码将能够正常工作,但速度会变慢。
vector<pair<int, int>>spellOne;

for (int i = 0; i < nSpellOne; i++)
{
    int input;
    if(std::cin >> input)
        spellOne.emplace_back(input, 0);
    else
        break;
}

for(std::pair<int, int> & data : spellOne) {
    int input;
    if(std::cin >> input)
        data.second = input;
    else
        break;
}

auto it = std::remove_if(
    spellOne.begin(),
    spellOne.end(),
    [mana](std::pair<int, int> const& data) {
        if(data.second > mana) return true;
        else return false;
    }
);

spellOne.erase(it, spellOne.end());

这实际上是一个很棒的解决方案,我会考虑将其与其他答案合并,并且它非常清晰地解释了有关向量的一些我之前没有考虑到的问题。另外,最近有人告诉我scanf函数比std::cin快一点,但是根据你的回答,我想那可能是个谎言,哈哈。谢谢! - saras
1
@Sara scanf 可能比 std::cin 更快(尽管我没有看到证据表明在实际应用中可以节省大量时间),但是 std::cin 提供了各种错误检查机制,而 scanf 则忽略了这些机制。这里的好处不仅仅是速度,更重要的是确保当用户执行意外操作时(例如提供非数字输入)程序能够负责任地处理。 - Xirema
好的,emplace_back 函数运行得非常好,我已经成功地使用它了,我甚至从未考虑过它,所以谢谢! - saras

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接