如何在没有循环的情况下在 C++ 中总结 vector int 的向量
how to sum up a vector of vector int in C++ without loops
我尝试以非循环方式实现对 vector<vector<int>>
的所有元素求和。
之前查过一些相关问题,How to sum up elements of a C++ vector?.
所以我尝试使用 std::accumulate
来实现它,但我发现我很难在 std::accumulate
中重载 Binary Operator
并实现它。
所以我对如何用 std::accumulate
实现它感到困惑,或者有更好的方法吗?
如果不介意谁能帮帮我?
提前致谢。
根据 https://en.cppreference.com/w/cpp/algorithm/accumulate ,看起来 BinaryOp 在左侧有当前总和,在右侧有下一个范围元素。所以你应该 运行 std::accumulate 在右侧参数上,然后将它与左侧参数和 return 结果相加。如果您使用 C++14 或更高版本,
auto binary_op = [&](auto cur_sum, const auto& el){
auto rhs_sum = std::accumulate(el.begin(), el.end(), 0);
return cur_sum + rhs_sum;
};
虽然我没有尝试编译代码:)。如果我弄乱了参数的顺序,只需替换它们即可。
编辑:术语错误 - 你没有过载 BinaryOp,你只是传递它。
您需要使用 std::accumulate
两次,一次用于外部 vector
和一个二元运算符,该运算符知道如何使用对 [=11= 的额外调用对内部 vector
求和]:
int sum = std::accumulate(
vec.begin(), vec.end(), // iterators for the outer vector
0, // initial value for summation - 0
[](int init, const std::vector<int>& intvec){ // binaryOp that sums a single vector<int>
return std::accumulate(
intvec.begin(), intvec.end(), // iterators for the inner vector
init); // current sum
// use the default binaryOp here
}
);
在这种情况下,我不建议使用std::accumulate
,因为它会大大影响可读性。此外,此函数在内部使用循环,因此您不会保存任何内容。只需将以下基于循环的解决方案与使用 std::accumulate
:
的其他答案进行比较
int result = 0 ;
for (auto const & subvector : your_vector)
for (int element : subvector)
result += element;
结合使用迭代器、STL 函数和 lambda 函数是否会使您的代码更易于理解且速度更快?对我来说,答案很明确。循环并不邪恶,尤其是对于这种简单的应用程序。
std::accumulate
的签名是:
T accumulate( InputIt first, InputIt last, T init,
BinaryOperation op );
注意return值是从init
参数推导出来的(不一定是InputIt
的value_type
)。
二进制运算为:
Ret binary_op(const Type1 &a, const Type2 &b);
其中...(来自 cppreference)...
The type Type1
must be such that an object of type T
can be implicitly converted to Type1
. The type Type2
must be such that an object of type InputIt
can be dereferenced and then implicitly converted to Type2
. The type Ret
must be such that an object of type T
can be assigned a value of type Ret
.
然而,当T
是InputIt
的value_type
时,以上更简单,你有:
using value_type = std::iterator_traits<InputIt>::value_type;
T binary_op(T,value_type&).
您的最终结果应该是 int
,因此 T
是 int
。您需要两次调用两次 std::accumulate
,一次用于外部向量(其中 value_type == std::vector<int>
),一次用于内部向量(其中 value_type == int
):
#include <iostream>
#include <numeric>
#include <iterator>
#include <vector>
template <typename IT, typename T>
T accumulate2d(IT outer_begin, IT outer_end,const T& init){
using value_type = typename std::iterator_traits<IT>::value_type;
return std::accumulate( outer_begin,outer_end,init,
[](T accu,const value_type& inner){
return std::accumulate( inner.begin(),inner.end(),accu);
});
}
int main() {
std::vector<std::vector<int>> x{ {1,2} , {1,2,3} };
std::cout << accumulate2d(x.begin(),x.end(),0);
}
基于嵌套的解决方案std::accumulate
可能难以理解。
通过使用中间和的一维数组,解决方案可以更直接(但可能效率较低)。
int main()
{
// create a unary operator for 'std::transform'
auto accumulate = []( vector<int> const & v ) -> int
{
return std::accumulate(v.begin(),v.end(),int{});
};
vector<vector<int>> data = {{1,2,3},{4,5},{6,7,8,9}}; // 2D array
vector<int> temp; // 1D array of intermediate sums
transform( data.begin(), data.end(), back_inserter(temp), accumulate );
int result = accumulate(temp);
cerr<<"result="<<result<<"\n";
}
对 transform
的调用累积每个内部数组以初始化一维 temp
数组。
为避免循环,您必须专门添加每个元素:
std::vector<int> database = {1, 2, 3, 4};
int sum = 0;
int index = 0;
// Start the accumulation
sum = database[index++];
sum = database[index++];
sum = database[index++];
sum = database[index++];
不保证std::accumulate
会是非循环的(没有循环)。如果您需要避免循环,则不要使用它。
恕我直言,使用循环没有任何问题:for
、while
或 do-while
。具有用于对数组求和的专门指令的处理器使用循环。循环是保存代码的便捷方法 space。但是,有时可能需要 展开 循环(出于性能原因)。您可以有一个循环,其中包含展开或展开的内容。
使用 range-v3(很快就会使用 C++20),您可能会这样做
const std::vector<std::vector<int>> v{{1, 2}, {3, 4, 5, 6}};
auto flat = v | ranges::view::join;
std::cout << std::accumulate(begin(flat), end(flat), 0);
我尝试以非循环方式实现对 vector<vector<int>>
的所有元素求和。
之前查过一些相关问题,How to sum up elements of a C++ vector?.
所以我尝试使用 std::accumulate
来实现它,但我发现我很难在 std::accumulate
中重载 Binary Operator
并实现它。
所以我对如何用 std::accumulate
实现它感到困惑,或者有更好的方法吗?
如果不介意谁能帮帮我?
提前致谢。
根据 https://en.cppreference.com/w/cpp/algorithm/accumulate ,看起来 BinaryOp 在左侧有当前总和,在右侧有下一个范围元素。所以你应该 运行 std::accumulate 在右侧参数上,然后将它与左侧参数和 return 结果相加。如果您使用 C++14 或更高版本,
auto binary_op = [&](auto cur_sum, const auto& el){
auto rhs_sum = std::accumulate(el.begin(), el.end(), 0);
return cur_sum + rhs_sum;
};
虽然我没有尝试编译代码:)。如果我弄乱了参数的顺序,只需替换它们即可。
编辑:术语错误 - 你没有过载 BinaryOp,你只是传递它。
您需要使用 std::accumulate
两次,一次用于外部 vector
和一个二元运算符,该运算符知道如何使用对 [=11= 的额外调用对内部 vector
求和]:
int sum = std::accumulate(
vec.begin(), vec.end(), // iterators for the outer vector
0, // initial value for summation - 0
[](int init, const std::vector<int>& intvec){ // binaryOp that sums a single vector<int>
return std::accumulate(
intvec.begin(), intvec.end(), // iterators for the inner vector
init); // current sum
// use the default binaryOp here
}
);
在这种情况下,我不建议使用std::accumulate
,因为它会大大影响可读性。此外,此函数在内部使用循环,因此您不会保存任何内容。只需将以下基于循环的解决方案与使用 std::accumulate
:
int result = 0 ;
for (auto const & subvector : your_vector)
for (int element : subvector)
result += element;
结合使用迭代器、STL 函数和 lambda 函数是否会使您的代码更易于理解且速度更快?对我来说,答案很明确。循环并不邪恶,尤其是对于这种简单的应用程序。
std::accumulate
的签名是:
T accumulate( InputIt first, InputIt last, T init,
BinaryOperation op );
注意return值是从init
参数推导出来的(不一定是InputIt
的value_type
)。
二进制运算为:
Ret binary_op(const Type1 &a, const Type2 &b);
其中...(来自 cppreference)...
The type
Type1
must be such that an object of typeT
can be implicitly converted toType1
. The typeType2
must be such that an object of typeInputIt
can be dereferenced and then implicitly converted toType2
. The typeRet
must be such that an object of typeT
can be assigned a value of typeRet
.
然而,当T
是InputIt
的value_type
时,以上更简单,你有:
using value_type = std::iterator_traits<InputIt>::value_type;
T binary_op(T,value_type&).
您的最终结果应该是 int
,因此 T
是 int
。您需要两次调用两次 std::accumulate
,一次用于外部向量(其中 value_type == std::vector<int>
),一次用于内部向量(其中 value_type == int
):
#include <iostream>
#include <numeric>
#include <iterator>
#include <vector>
template <typename IT, typename T>
T accumulate2d(IT outer_begin, IT outer_end,const T& init){
using value_type = typename std::iterator_traits<IT>::value_type;
return std::accumulate( outer_begin,outer_end,init,
[](T accu,const value_type& inner){
return std::accumulate( inner.begin(),inner.end(),accu);
});
}
int main() {
std::vector<std::vector<int>> x{ {1,2} , {1,2,3} };
std::cout << accumulate2d(x.begin(),x.end(),0);
}
基于嵌套的解决方案std::accumulate
可能难以理解。
通过使用中间和的一维数组,解决方案可以更直接(但可能效率较低)。
int main()
{
// create a unary operator for 'std::transform'
auto accumulate = []( vector<int> const & v ) -> int
{
return std::accumulate(v.begin(),v.end(),int{});
};
vector<vector<int>> data = {{1,2,3},{4,5},{6,7,8,9}}; // 2D array
vector<int> temp; // 1D array of intermediate sums
transform( data.begin(), data.end(), back_inserter(temp), accumulate );
int result = accumulate(temp);
cerr<<"result="<<result<<"\n";
}
对 transform
的调用累积每个内部数组以初始化一维 temp
数组。
为避免循环,您必须专门添加每个元素:
std::vector<int> database = {1, 2, 3, 4};
int sum = 0;
int index = 0;
// Start the accumulation
sum = database[index++];
sum = database[index++];
sum = database[index++];
sum = database[index++];
不保证std::accumulate
会是非循环的(没有循环)。如果您需要避免循环,则不要使用它。
恕我直言,使用循环没有任何问题:for
、while
或 do-while
。具有用于对数组求和的专门指令的处理器使用循环。循环是保存代码的便捷方法 space。但是,有时可能需要 展开 循环(出于性能原因)。您可以有一个循环,其中包含展开或展开的内容。
使用 range-v3(很快就会使用 C++20),您可能会这样做
const std::vector<std::vector<int>> v{{1, 2}, {3, 4, 5, 6}};
auto flat = v | ranges::view::join;
std::cout << std::accumulate(begin(flat), end(flat), 0);