Знакомясь с возможностями C++20 наткнулся на статью здесь
Предлагается решить задачу:
Допустим, есть вектор с целыми числами, и требуется поделить все его числа на два. Те, которые не делятся, нужно просто выкинуть. Это несложно написать циклом, но для выразительности воспользуемся алгоритмами:
std:vector<int> numbers_in;
std:vector<int> numbers_out;
// задача: поделить на 2 все чётные числа из numbers_in
// и записать результаты numbers_out
std:vector<int> intermediate;
// скопируем в intermediate только чётные числа
std::copy_if(numbers_in.begin(), numbers_in.end(),
std::back_inserter(intermediate),
[](int x) {
return x % 2 == 0;
}
);
// поделим их на 2
std::transform(intermediate.begin(), intermediate.end(),
std::back_inserter(numbers_out),
[](int x) {
return x / 2;
}
)
Немного удивившись такому решению, быстрым поиском нашёл похожее у MS здесь
Почему так сложно? Ведь задача решается в одну строчку:
std::remove_if(numbers_in.begin(), numbers_in.end(), [](int& x){ const int s = x; x /= 2; return (s%2)==1; } );
Исправление (забыл отрезать хвост):
numbers_in.erase(std::remove_if(numbers_in.begin(), numbers_in.end(), [](int& x){ const int s = x; x /= 2; return (s%2)==1; } ), numbers_in.end());
Здравствуйте, B0FEE664, Вы писали:
BFE>Немного удивившись такому решению, быстрым поиском нашёл похожее у MS здесь BFE>Почему так сложно? Ведь задача решается в одну строчку: BFE>
BFE>std::remove_if(numbers_in.begin(), numbers_in.end(), [](int& x){ const int s = x; x /= 2; return (s%2)==1; } );
BFE>
BFE>Или так нельзя?
Ну, во-первых, правильно выше подсказывают, здесь не хватает вызова erase. И если его добавить, то твоя строчка становится чуть длиннее:
numbers_in.erase(std::remove_if(numbers_in.begin(), numbers_in.end(), [](int& x){ const int s = x; x /= 2; return (s%2)==1; } ), numbers_in.end());
Во-вторых, по условию задачи результат нужно было сложить в другой массив, а ты удаляешь прямо в исходном. Или ты собираешься сперва скопировать все содержимое, а потом уже удалять? Это вообще не спортивно.
Ну и в-третьих, а чем, в данном случае, хуже "лобовое" решение с использованием обычного цикла?
for(int x : numbers_in) if (!(x % 2)) numbers_out.push_back(x / 2);
А, ну и по сути вопроса — "почему так сложно?" — а ХЗ, почему. Мозги у людей как-то странно сложены.
for(int x : numbers_in) if (!(x % 2)) numbers_out.push_back(x / 2);
bnk>Особенно сравнивая с нормальными языками
bnk>
numbers_in.filter(x => x % 2 == 0).map(x => x / 2)
Ну ты же жульничаешь — ты не положил числа в выходной массив. Ты предоставть законченное решение, тогда и сравним.
И запись, с которой сравниваешь, удалил зачем-то. Наверное, для того, чтобы сделать сравнение максимально наглядным
А во-вторых, в С++ тоже можно решить эту задачу в функциональном стиле и с lazy evaluation. Необходимая поддержка для этого давно уже есть в boost и сравнительно недавно появилась в стандартной библиотеке, в std::ranges:
numbers_in.filter(x => x % 2 == 0).map(x => x / 2)
R>Ну ты же жульничаешь — ты не положил числа в выходной массив. Ты предоставть законченное решение, тогда и сравним.
R>И запись, с которой сравниваешь, удалил зачем-то. Наверное, для того, чтобы сделать сравнение максимально наглядным
Ну совсем немного и сжульничал
R>А во-вторых, в С++ тоже можно решить эту задачу в функциональном стиле и с lazy evaluation. Необходимая поддержка для этого давно уже есть в boost и сравнительно недавно появилась в стандартной библиотеке, в std::ranges:
R>
numbers_in.filter(x => x % 2 == 0).map(x => x / 2)
R>>Ну ты же жульничаешь — ты не положил числа в выходной массив. Ты предоставть законченное решение, тогда и сравним.
S>Это, кстати, от языка зависит. В некоторых языках map именно что создает новый контейнер:
Ну, как минимум, нужно сделать присваивание (инициализацию) — в любом языке. А если это
C# (пардон, если не угадал), то еще и добавить преобразование к нужному типу. И если это сделать, то совсем не понятно, ради чего нужно было заводить очередной холивар:
numbers_out = numbers_in.filter(x => x % 2 == 0).map(x => x / 2).ToArray<int>();
for(int x : numbers_in) if (!(x % 2)) numbers_out.push_back(x / 2);
Здравствуйте, rg45, Вы писали:
R>Ну ты же жульничаешь — ты не положил числа в выходной массив.
это как акцент поставить. До С++20 нельзя сделать std::transform без создания выходного массива. В оригинальной статье явно этот момент и отмечался.
Там же есть уточнение:
Но если всё же вам необходимо вычислить всё сразу, вы можете по старинке сложить все элементы диапазона в какой-нибудь контейнер:
Здравствуйте, sergii.p, Вы писали:
SP>это как акцент поставить. До С++20 нельзя сделать std::transform без создания выходного массива. В оригинальной статье явно этот момент и отмечался.
Здравствуйте, rg45, Вы писали:
R>Во-вторых, по условию задачи результат нужно было сложить в другой массив, а ты удаляешь прямо в исходном. Или ты собираешься сперва скопировать все содержимое, а потом уже удалять? Это вообще не спортивно.
Нет, это в примере решена не та задача, которая поставлена.
R>Ну и в-третьих, а чем, в данном случае, хуже "лобовое" решение с использованием обычного цикла? R>
R> for(int x : numbers_in) if (!(x % 2)) numbers_out.push_back(x / 2);
R>
Ну, если добавить const:
for(const int x : numbers_in) if (!(x % 2)) numbers_out.push_back(x / 2);
то нормально, если нам действительно нужно копирование.
R>А, ну и по сути вопроса — "почему так сложно?" — а ХЗ, почему. Мозги у людей как-то странно сложены.
Мне кажется, что подобную задачу в качестве примера я не первый раз встречаю. Все её решают почему-то через промежуточный буфер... Отсюда и вопрос.
Здравствуйте, B0FEE664, Вы писали:
BFE>Нет, это в примере решена не та задача, которая поставлена.
Ну, так а я тут при чем? Я вижу в ТВОЕМ сообщении формулировку: "задача: поделить на 2 все чётные числа из numbers_in и записать результаты в numbers_out". Я же с тобой общаюсь, поэтому то, что написано тобой я рассматриваю с более высоким приоритетом чем то, что находится по ссылкам. А если в твоем сообщении присутствуют противоречащие друг другу формулировки, то это твоя забота рассказать, что читать, а что игнорировать. В чем я не прав?
BFE>Ну, если добавить const: BFE>
BFE>for(const int x : numbers_in) if (!(x % 2)) numbers_out.push_back(x / 2);
BFE>
BFE>то нормально, если нам действительно нужно копирование.
И почему здесь так важен этот const, не объяснишь? Помимо правил хорошего стиля.
Здравствуйте, B0FEE664, Вы писали:
BFE>Знакомясь с возможностями C++20 наткнулся на статью здесь BFE>Предлагается решить задачу: BFE>[q] BFE>Допустим, есть вектор с целыми числами, и требуется поделить все его числа на два. Те, которые не делятся, нужно просто выкинуть.