【问题标题】:Removing elements by index in vector pairs按向量对中的索引删除元素
【发布时间】:2017-01-17 20:14:18
【问题描述】:

我在第一个和第二个位置都有整数向量对,并且输入相当具体。
首先,我有 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 提供负值)
  • 我尝试使用向量的擦除函数来执行此操作,但我得到一个错误,因为我需要指定第一个或第二个位置,并且当我构建程序来擦除 spellOne.erase(spellOne. begin() + i),程序崩溃,说向量迭代器偏移超出范围。
  • 是的,这是有道理的 Sara,请查看我作为答案发布的示例,应该足以让您得到提升! ;)

标签: c++ vector std-pair


【解决方案1】:

我举了一个例子,它应该可以帮助你完成任务。在下面的示例中,我填充向量,然后删除第二个值大于某个阈值(在本例中为 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++;
}

PS - 编写高效代码时,不要在意 std::cinscanf() 是否更快,专注于您的算法!

【讨论】:

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

首先,您加载向量的代码并不完全正确。

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
}

std::vector 不只是神奇地为您查询的任何元素提供空间:您必须专门使用将元素插入向量中的方法,无论是 emplace_back(理想)、emplace、@ 987654325@,或insertback 只请求最后的元素,如果有问题的元素不存在,或者您希望它在每次调用时返回一个唯一元素,则会产生不好的结果。

那么,在遍历向量时,正确使用 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 快一点,但我想这是一个谎言,从你的回答来看,哈哈。谢谢!
  • @Sara scanf 可能比std::cin 更快(尽管我没有看到任何证据表明它在实际应用程序中可以显着节省),但std::cin 提供了广泛的scanf 掩盖的各种错误检查机制。此处的好处与其说是速度,不如说是确保您的程序在用户执行意外操作(例如,提供非数字输入)时能够负责任地运行。
  • 好的,emplace_back 功能就像一个魅力,我做得很好,我从来没有考虑过,所以谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
  • 2021-10-28
  • 1970-01-01
  • 1970-01-01
  • 2014-05-05
  • 2017-12-16
  • 1970-01-01
相关资源
最近更新 更多