Я получил код в следующем виде
vector<int> vec{ 1,2,3 };
vector<int> vec2{ 4, 5, 6, 7, 8, 9 };
for (int i = 0; i < vec2.size(); i++) {
if (vec2[i] % 2 == 0)
vec.push_back(vec2[i]);
}
Как я могу использовать std::transform
, чтобы избавиться от цикла for? Спасибо за помощь :)
Я попробовал что-то вроде:
std::transform(vec2.begin(), vec2.end(), std::back_inserter(vec), ...);
но я не уверен, что добавить в последнее место (где ...
).
Если серьезно, мне нравится ваш код таким, какой он есть. Я могу точно видеть, что происходит.
@Джейсон С std::copy_if
вы также точно знаете, что происходит, плюс преимущество краткости (повышенная читабельность).
Это ваше мнение, и это нормально. Я не согласен по поводу читабельности, но это субъективно.
На мой взгляд, если в этом коде используется for на основе диапазона, он будет гораздо более читаемым, чем std::copy_if
с обратной вставкой и лямбда-выражением. По крайней мере, этой лямбде следует дать имя.
transform
предназначен для преобразования типов элементов, а не для фильтрации.
Вы не можете быть более явным, чем «копировать, если», поскольку OP в основном хочет скопировать vec2 в vec1, если <условие> (хорошие имена в сочетании с краткостью делают читабельность)
@Fareanor Я вижу твой аргумент и не совсем с ним согласен. Мы просто не согласны с тем, как мы определяем читабельность. Если мы предположим, что в компании полно RocketSearchers (неплохо), каждый в компании сможет прочитать исходный код и без вопросов точно понять, что происходит. Он не знал ни о std::copy_if
, ни о его аргументах, ни о его предостережениях, ни о его последствиях для производительности. Так что, если он встретит это в коде, он окажет себе медвежью услугу, не остановившись и не просмотрев документацию. Так что, на мой взгляд, оригинал читабельнее.
Я бы не стал использовать std::transform()
для этого. Петля подойдет, но любители удаления петель могут использовать std::copy_if (vec.begin(), vec.end(), std::back_inserter(vec2),[](int x) {return x % 2 == 0; });
.
Вы в корне неправильно понимаете, что такое std::transform
. Это не замена всех петель for
. Скорее, for
— это конструкция языка низкого уровня, которую можно использовать для выражения различных алгоритмов в разных диапазонах. std::transform
— один из таких алгоритмов. Но цикл, который у вас есть, выражает другой алгоритм (который обычно известен как filter
, но в C++ он имеет другое имя — точно так же, как C++ std::transform
обычно известен под разными именами, например map
).
std::transform
— неправильный инструмент для работы. Он не может фильтровать элементы по условию, все элементы из входного диапазона должны быть помещены (после преобразования) в выходной диапазон.
Вместо этого используйте std::copy_if:
std::copy_if (vec2.begin(), vec2.end(), std::back_inserter(vec), [](int i){return i % 2 == 0;});
Вам нужно std::copy_if
:
std::vector<int> vec{ 1,2,3 };
std::vector<int> vec2{ 4, 5, 6, 7, 8, 9 };
std::copy_if (vec2.cbegin(),vec2.cend(),std::back_inserter(vec),[](const int num){
return num % 2 == 0;
});
for(auto&& i : vec) {
std::cout << i;
}
std::copy_if
копирует элемент из одного диапазона в другой, используя предикат в качестве критерия выбора.
std::transform
— это отображение одного диапазона в другой: T -> Transform -> U
Цикл вывода можно заменить на std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(std::cout, " "));
(при выводе vec
, в противном случае вместо него выведите vec2
).
Было бы лучше переместить лямбду в именованную переменную isEven
, чтобы было понятно, что происходит, без анализа ее тела.
@Peter ostream_iterator очень шумный из-за печати такого простого вектора
@Raildex Вызов copy_if ()
так же шумен (особенно потому, что цикл OP можно легко записать в форме, аналогичной выходному циклу, чтобы подчеркнуть этот шум). Я хочу сказать, что если цель состоит в том, чтобы избежать (явного) написания циклов, есть варианты.
Кроме того, почему у вас проблемы с циклами? Я бы просто заменил
for
на более приятный:for (int value: vec2) { if (value%2==0) vec.push_back(value); }