std :: remove_if - лямбда, не удаляя ничего из коллекции
-
11-10-2019 - |
Вопрос
Хорошо, я ожидаю, что я сделал тупой ошибку здесь. У меня есть список DisplayDevice3D, и каждый DisplayDevice3D содержит список DisplayMode3D. Я хочу удалить все элементы из списка DisplayDevice3D, у которых нет никаких DisplayMode3D. Я пытаюсь использовать лямбду, чтобы сделать это, т.е.:
// If the device doesn't have any modes, remove it.
std::remove_if(MyDisplayDevices.begin(), MyDisplayDevices.end(),
[](DisplayDevice3d& device)
{
return device.Modes.size() == 0;
}
);
Несмотря на то, что из 6 DisplayMode3D в MyDisPlayDevices, только 1 имеет какие -либо DisplayMode3D в своей коллекции режимов, из списка ничего не удаляется.
Какую ошибку я здесь допустили?
Редактировать:
Ах, ладно, моя ошибка заключалась в том, что я должен использовать mydisplaydevices.remove_if вместо std :: remove_if, однако ответы ниже верны для использования std :: remove_if: p.
MyDisplayDevices.remove_if( [](DisplayDevice3d const & device)
{
return device.Modes.size() == 0;
});
Решение
Вам нужно вызвать стирание на итераторе, возвращенном из remove_if, он должен выглядеть примерно так:
auto new_end = std::remove_if(MyDisplayDevices.begin(), MyDisplayDevices.end(),
[](const DisplayDevice3d& device)
{ return device.Modes.size() == 0; });
MyDisplayDevices.erase(new_end, MyDisplayDevices.end());
Другие советы
remove_if
ничего не удаляет из списка, это просто перемещает их к концу. Вам нужно использовать его вместе с erase
. Анкет Посмотри это вопрос Больше подробностей.
Как упоминали другие, есть способы заставить его работать. Однако мой совет - полностью избежать remove_if
и вместо этого придерживайтесь стандартного удаления на основе итератора. Идиома ниже работает как для list
а также vector
и не производит неожиданное поведение.
for( vector<TYPE>::iterator iter = vec.begin() ; iter != vec.end() ; )
if( iter->shouldRemove )
iter = vec.erase( iter ) ; // advances iter
else
++iter ; // don't remove
Как упоминалось в комментариях ниже, этот метод имеет более высокую стоимость, чем remove_if
Когда удаляется более 1 элемента.
remove_if
Работает, копируя элементы с дальше впереди в векторе и перезаписывая векторы, которые должны быть удалены из вектора сразу перед ним. Например: remove_if вызова вектор, чтобы удалить все 0 элементов:
0 1 1 0 1 0
Результаты:
1 1 1 0 1 0
Обратите внимание, как вектор еще не прав. Это потому remove_if
Возвращает итератор в последний допустимый элемент ... он не автоматически изменяет размер вектора. Вам все еще нужно позвонить v.erase()
На итераторе вернулся с вашего звонка в remove_if
.
Пример ниже
#include <stdio.h>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
void print( vector<int> &v )
{
for( int i : v )
printf( "%d ", i );
puts("");
}
int main()
{
vector<int> v = { 0, 1, 1, 0, 1, 0 };
print( v ); // 0 1 1 0 1 0
vector<int>::iterator it = remove_if( v.begin(), v.end(), [](int i){ return i == 0; } );
print( v ); // 1 1 1 0 1 0
v.erase( it, v.end() ); // actually cut out values not wanted in vector
print( v ); // 1 1 1 (correct)
}