сумма квадратов каждого элемента в векторе, использующаяся для каждого
как функция, принятая 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
имитировать "шаблон программирования", как карта и вводить в 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
EDIT: спасибо всем. Я многому научился из ваших ответов. У нас так много способов сделать одну и ту же вещь на 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:: accumulate как в хороший ответ GMan, но я считаю, что использование std:: accumulate сделает ваш код более читаемым, потому что он был разработан для таких целей. Вы можете найти более стандартные алгоритмы здесь.
нет, не используйте std::accumulate() используйте 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()
С :
#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
шаблон класса, который принимает любой числовой тип.
в качестве общего решения такой проблемы с STL: вместо передачи функции вы можете передать functor
-- например, экземпляр любого класса, реализующего operator()
. Это намного лучше, чем полагаться на глобальные переменные, так как указанный экземпляр может сохранять и обновлять свое собственное состояние! Вы можете думать об этом как о своего рода "типизации утки времени компиляции": общее Программирование не ограничивает вас передавать "функцию" в этом месте, все, что "ведет себя как функция" (т. е. имеет правильное operator()
) сделаем так же!-)
std::for_each
для того, чтобы что-то делать с каждого элемент. Если вы хотите получить результат от расчета на все элементы, есть std::accumulate
. Если вы желаете поведение, используйте std::transform
.
вы можете злоупотреблять любым из этих трех, чтобы сделать то же самое, что и любой из других, так как в конечном итоге они просто повторяют итератор (за исключением transform
форма, которая принимает два итератора в качестве входных данных.) Дело в том, что for_each
is не замена map / fold - это должно быть сделано с помощью transform/accumulate - хотя C++ изначально не имеет чего - то, что выражает концепцию map / fold так же, как Haskell, но и gcc и VC++ поддерживают OpenMP, который имеет гораздо лучший аналог в #pragma omp parallel for
.
Inject в 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;
}