Сумма квадрата каждого элемента в векторе, используя for_each
Поскольку функция, принятая for_each, принимает только один параметр (элемент вектора), я должен определить static int sum = 0
где-то, чтобы к нему можно было получить доступ после вызова for_each . Я думаю, что это неловко. Есть ли лучший способ сделать это (по-прежнему использовать for_each)?
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
static int sum = 0;
void add_f(int i )
{
sum += i * i;
}
void test_using_for_each()
{
int arr[] = {1,2,3,4};
vector<int> a (arr ,arr + sizeof(arr)/sizeof(arr[0]));
for_each( a.begin(),a.end(), add_f);
cout << "sum of the square of the element is " << sum << endl;
}
В Ruby мы можем сделать это следующим образом:
sum = 0
[1,2,3,4].each { |i| sum += i*i} #local variable can be used in the callback function
puts sum #=> 30
Не могли бы вы показать больше примеров, как for_each
обычно используется в практическом программировании (а не просто распечатывать каждый элемент)? Возможно ли использовать for_each
имитировать "шаблон программирования", такой как map и вставлять в Ruby (или map /fold в Haskell).
#map in ruby
>> [1,2,3,4].map {|i| i*i}
=> [1, 4, 9, 16]
#inject in ruby
[1, 4, 9, 16].inject(0) {|aac ,i| aac +=i} #=> 30
РЕДАКТИРОВАТЬ: Спасибо всем. Я так много узнал из твоих ответов. У нас так много способов сделать одну и ту же вещь в C++, что немного усложняет изучение. Но это интересно:)
6 ответов
Используйте std:: накопить
#include <vector>
#include <numeric>
// functor for getting sum of previous result and square of current element
template<typename T>
struct square
{
T operator()(const T& Left, const T& Right) const
{
return (Left + Right*Right);
}
};
void main()
{
std::vector <int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
int x = std::accumulate( v1.begin(), v1.end(), 0, square<int>() );
// 0 stands here for initial value to which each element is in turn combined with
// for our case must be 0.
}
Вы можете эмулировать std:: накапливать, как в ответе хорошего GMan, но я считаю, что использование std:: накапливать сделает ваш код более читабельным, потому что он был разработан для таких целей. Вы можете найти более стандартные алгоритмы здесь.
Нет, не используйте std:: аккумуляцию (), используйте std::inner_product(). Функтор не требуется.
#include <vector>
#include <numeric>
void main()
{
std::vector <int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
int x = std::inner_product( v1.begin(), v1.end(), v1.begin(), 0 );
}
for_each
возвращает (копию) функтор, который он использовал. Итак, как то так:
#include <algorithm>
#include <vector>
#include <iostream>
template <typename T>
class square_accumulate
{
public:
square_accumulate(void) :
_sum(0)
{
}
const T& result(void) const
{
return _sum;
}
void operator()(const T& val)
{
_sum += val * val;
}
private:
T _sum;
};
int main(void)
{
int arr[] = {1,2,3,4};
std::vector<int> a (arr ,arr + sizeof(arr)/sizeof(arr[0]));
int sum = std::for_each(a.begin(), a.end(), square_accumulate<int>()).result();
std::cout << "sum of the square of the element is " << sum << std::endl;
}
Как показали другие ответы, std::accumulate
это лучший способ пойти.
Не использовать for_each()
для этого используйте accumulate()
от <numeric>
заголовок:
#include <numeric>
#include <iostream>
using namespace std;
struct accum_sum_of_squares {
// x contains the sum-of-squares so far, y is the next value.
int operator()(int x, int y) const {
return x + y * y;
}
};
int main(int argc, char **argv) {
int a[] = { 4, 5, 6, 7 };
int ssq = accumulate(a, a + sizeof a / sizeof a[0], 0, accum_sum_of_squares());
cout << ssq << endl;
return 0;
}
Поведение по умолчанию accumulate()
заключается в суммировании элементов, но вы можете предоставить свою собственную функцию или функтор, как мы это делаем здесь, и выполняемая ими операция не обязательно должна быть ассоциативной - 2-й аргумент всегда является следующим элементом, с которым нужно работать. Эта операция иногда называется reduce
на других языках.
Вы можете использовать простую функцию вместо accum_sum_of_squares
функтор, или для еще большей универсальности, вы можете сделать accum_sum_of_squares
шаблон класса, который принимает любой числовой тип.
std::for_each
для того, чтобы сделать что-то с каждым элементом. Если вы хотите получить результат из расчета по всем элементам, есть std::accumulate
, Если вы хотите Haskell's map
поведение, использование std::transform
,
Вы можете злоупотребить любым из этих трех, чтобы сделать то же самое, что и любой другой, так как в конечном итоге они просто перебирают итератор (за исключением transform
форма, которая принимает два итератора в качестве входных данных.) Дело в том, что for_each
не является заменой map/fold - это должно быть сделано с помощью transform/ аккумулирования - хотя в C++ изначально нет того, что выражает концепцию map / fold, как это делает Haskell, - но и gcc, и VC++ поддерживают OpenMP, который имеет много лучший аналог в #pragma omp parallel for
,
Inject in Ruby намного ближе к коллу for_each
с полноценным функтором, как объяснил GMan выше. Лямбда-функции с захватом переменных в C++0X сделают поведение между двумя языками еще более похожим:
int main(void)
{
int arr[] = {1,2,3,4};
std::vector<int> a (arr ,arr + sizeof(arr)/sizeof(arr[0]));
int sum = 0;
std::for_each(a.begin(), a.end(), [&](int i) { sum += i*i;} );
std::cout << "sum of the square of the element is " << sum << std::endl;
}
Как общее решение такой проблемы с STL: вместо передачи функции вы можете передать functor
- например, экземпляр любого класса, реализующего operator()
, Это гораздо лучше, чем полагаться на глобальные переменные, поскольку указанный экземпляр может сохранять и обновлять свое собственное состояние! Вы можете думать об этом как о "типизированной утке во время компиляции": универсальное программирование не ограничивает вас передачей "функции" в этом месте, всего, что "ведет себя как функция" (т. Е. Имеет operator()
) так же сделаю!-)