2017-01-17 3 views
2

У меня есть векторные пары целых чисел как в первой, так и в второй позиции, а вход довольно конкретный.
Во-первых, у меня есть входы, которые все входят в первые пятна вектора, но потом идет второй массив входов, который должен идти во вторую позицию.
Однако, что бы я хотел сделать, есть ли условие, что если я нахожу вход второго места больше определенного значения (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; 
    } 
} 

Может кто-нибудь помочь мне о том, как сделать это, и если это вообще возможно, или я должен переключиться на другой тип массивов? Я также рассматривал использование карт, но это было невозможно, так как есть высокая вероятность получить одно и то же значение дважды в первом/втором месте в векторе, поэтому я не могу использовать их в качестве ключа.

+0

Вам нужно удалить всю пару с индексом 'i', но затем уменьшить' i' на один тоже (осторожно, чтобы не дать отрицательное значение 'i', хотя) – gsamaras

+0

я пытался делать, что с стиранием функция для векторов, но я получаю сообщение об ошибке, поскольку мне нужно указать либо первую, либо вторую позицию, а когда я создаю программу для удаления spellOne.erase (spellOne.begin() + i), программа вылетает, заявляя смещение векторного итератора вне диапазона. – Sara

+0

Да, это имеет смысл, Сара, проверьте мой пример, который я опубликовал в качестве ответа, должно быть достаточно, чтобы вы смогли повысить! ;) – gsamaras

ответ

2

Я сделал пример, который должен помочь вам повысить вашу задачу. В моем примере ниже я заполняю вектор, а затем стираю пары, у которых второе значение больше определенного порога (в данном случае 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::cin или scanf() быстрее, сосредоточьтесь на своем алгоритме!

+0

Agh, я тайно надеялся, что будет эффективное решение просто удалить элемент на месте, но это также работает лучше, чем то, что я раньше имел, просто зацикливая всю вещь. Огромное спасибо! :) – Sara

+0

@Sara, когда вход поступает, вы не знаете, какую пару вам нужно удалить, если условие выполнено, поэтому вам нужно перевернуть вектор или вызвать 'std :: find()', который, вероятно, будет так же эффективно, как и мое решение. Добро пожаловать и спасибо за хороший вопрос! =) – gsamaras

+0

Я полагаю, что я просто вычислил, что 'i' будет работать как способ найти элемент, поскольку первый набор входных данных такой же длины, как и второй, следовательно, они будут в одной и той же позиции, но я забыл тот факт, что 'erase()' перемещает элементы назад. – Sara

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 
} 

std::vector «s не просто волшебно есть места для каких бы элементов вы запрос: вы должны конкретно использовать методы, которые вставляют элементы в вектор, будь то 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()); 
+0

Это действительно замечательное решение, я подумаю о слиянии его с другим ответом, и он объяснил то, что я не очень четко рассматривал в отношении векторов. Кроме того, мне недавно сказали, что функция scanf, по-видимому, немного быстрее, чем std :: cin, но я полагаю, что это была ложь, судя по вашему ответу, ха-ха. Спасибо! – Sara

+1

@Sara 'scanf' может быть очень быстрым, чем' std :: cin' (хотя я не видел никаких доказательств того, что это значительная экономия в реальных приложениях), но 'std :: cin' предлагает широкий выбор механизмов проверки ошибок, которые 'scanf' затушевывает. Преимущество здесь заключается не столько в скорости, сколько в том, чтобы убедиться, что ваша программа ведет себя ответственно, когда пользователь делает что-то неожиданное (например, для обеспечения нечислового ввода). – Xirema

+0

Хорошо, функция 'emplace_back' работает как прелесть, я прекрасно ее работаю, я даже не подумал об этом, поэтому спасибо! – Sara

Смежные вопросы