简体   繁体   中英

Removing elements by index in vector pairs

I have vector pairs of integers both on first and second position and the input is rather specific.
Firstly, I have i inputs that all go into the first spots of the vector, but afterwards comes the second array of inputs that's supposed to go to the second position.
However, what I'd like to do, is I have a condition that if I find an input of the second spot bigger than a certain value ( mana , in my case the variable), I'd like to simply not put it into the vector pair, and remove the first element on that index from the first position and I'm having trouble figuring out how to code it. Here's the part of that code:

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;
    }
}

Could anyone help me out on how to do that and if that's even possible, or should I switch to a different type of arrays? I also considered using maps, but that wasn't possible, since there's a high chance I get the same value twice in either first/second spot in the vector, hence I can't use any of them as a key.

I made an example, which should get you boosted to complete your task. In my example bellow I populate the vector and then erase the pairs that have a second value greater than a certain threshold (2 in this case).

Now you can use two variables to keep track of the loop that erases the elements, one to loop through the whole vector and one to keep track of the current index to be checked; if we remove v[3] , then the next element v[4] is shifted (because we called erase() ) in place of v[3] , thus we should examine index 3 again!

#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;
}

Output:

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

Edit for your comment: You could try that:

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

PS - When writing efficient code, don't bother for whether std::cin or scanf() is faster, focus on your algorithm!

First of all, your code for loading up the vector isn't entirely correct.

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 's don't just magically have space for whichever elements you query: you have to specifically use the methods that insert elements into the vector, whether it be emplace_back (ideal), emplace , push_back , or insert . back only requests the back-most element, and will have bad results if the element in question doesn't exist, or if you're expecting it to return a unique element per call.

Then, when iterating through the vector, proper use of the STL will simplify things greatly.

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());

This code does make a small change to your use case, where we're supplying the second number at the same time as the first number. So the input to this program will be 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 . If you really need your previous order (though I don't recommend it) this code will work fine, though will be slower.

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());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM