Efficient combined min and mean computation of a vector - c++

I need both the minimum and the mean of the values in a vector.
I'm computing them separately with the following:
template <class T>
T Minimum(std::vector<T> & v){ return *min_element(begin(v), end(v)); }
template <class T>
T Mean(std::vector<T> & v)
{
T sum = std::accumulate(v.begin(), v.end(), static_cast<T>(0));
T mean = sum / v.size();
return mean;
}
Both of these have to sweep the vector.
Is there a std efficient way to compute both minimum and mean of a vector sweeping it only once?

Yes, you can accumulate the minimum and the sum in the same call. No, it probably won't be more efficient, nor will it be less efficient.
template <typename T>
std::pair<T, T> MeanAndMin(const std::vector<T> & v)
{
auto zero = std::make_pair(static_cast<T>(0), std::numeric_limits<T>::max());
auto plus = [](auto pair, auto elem) { return std::make_pair(pair.first + elem, std::min(pair.second, elem)); };
auto res = std::accumulate(begin(v), end(v), zero, plus);
res.first /= v.size();
return res;
}

You can use std::accumulate, paired with custom functors:
#include <iostream>
#include <vector>
#include <numeric>
#include <limits>
#include <algorithm>
struct average_and_min {
int sum = 0;
int min = std::numeric_limits<int>::max();
std::size_t num_of_elements = 0;
int get_sum() {
return sum;
}
double get_average() {
return static_cast<double>(sum) / num_of_elements;
}
int get_min() {
return min;
}
};
int main() {
std::vector<int> vec = {1, 2, 5, 4, 4, 2, 4};
auto func_accumulate = [](average_and_min acc, int value) {
return average_and_min{acc.sum + value, std::min(acc.min, value), acc.num_of_elements + 1};
};
auto data = std::accumulate(vec.cbegin(), vec.cend(), average_and_min{}, func_accumulate);
std::cout << "avg: " << data.get_average() << '\n'
<< "min: " << data.get_min() << '\n';
}
EDIT:
As #Caleth suggested in the comments, it might be a good idea not to use lambdas to combine your struct and the value - you can overload operator + inside average_and_min like so:
average_and_min operator + (int value) {
return average_and_min{sum + value, std::min(min, value), num_of_elements + 1};
}
and the line
auto data = std::accumulate(vec.cbegin(), vec.cend(), average_and_min{}, func_accumulate);
can now become
auto data = std::accumulate(vec.cbegin(), vec.cend(), average_and_min{});

Related

sum up vectors in a matrix, element by element in c++

Is there a simple method in C++ that allows to sum up the vectors componing a matrix element by element? I mean, if I have the matrix M[3][4], I want the sum[3] vector with this components:
sum[0]=M[0][0]+M[1][0]+M[2][0]
sum[1]=M[0][1]+M[1][1]+M[2][1]
sum[2]=M[0][2]+M[1][2]+M[2][2]
I find out that exists this method for two vectors, I would like to extend it to many vectors, in particular to the std::vector<type>rows componing the matrix std::vector<vector<type> > M, not knowing a-priori the dimomension of M.
Is there a simple method in C++ that allows to sum up the vectors componing a matrix element by element? I mean, if I have the matrix M[3][4], I want the sum[3] vector with this components:
sum[0]=M[0][0]+M[1][0]+M[2][0]
sum[1]=M[0][1]+M[1][1]+M[2][1]
sum[2]=M[0][2]+M[1][2]+M[2][2]
Unfortunately, there is no simple method in the C++ standard library for adding
a container's elements column-wise.
There is std::accumulate(), but naturally, it would add up the row elements together, not the column elements, but we can fix that by iterating through each column index inside the matrix and adding up the elements one by one:
#include <iostream>
#include <numeric>
#include <cstddef>
#include <vector>
// The below function assumes that all columns of your matrix have the same length
template <typename T>
std::vector<T> m_col_add(std::vector<std::vector<T>> const& mat) {
std::vector<T> res;
const auto column_size = mat[0].size();
for (size_t x = 0; x < column_size; ++x)
res.push_back(std::accumulate(mat.begin(), mat.end(), T{}, [x](T const& a, std::vector<T> const& row) {
return a + row[x];
}));
return res;
}
int main() {
std::vector<std::vector<int>> mat {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
auto res = m_col_add(mat);
for (auto const& elem : res)
std::cout << elem << " ";
}
Output:
15 18 21 24
Alternatively, if you already know the sizes of the rows and columns during compile-time and are using C++17 or above, you can use fold expressions and std::index_sequence<> to add up the elements faster by compile-time expansion:
#include <iostream>
#include <utility>
#include <cstddef>
#include <array>
template <size_t Column, typename T, size_t Rows, size_t Columns, size_t ...Sizes>
T m_col_add_impl2(std::index_sequence<Sizes...>, std::array<std::array<T, Columns>, Rows> const& mat) {
return (mat[Sizes][Column] + ...);
}
template <typename T, size_t Rows, size_t Columns, size_t ...Sizes>
std::array<T, Columns> m_col_add_impl1(std::index_sequence<Sizes...>, std::array<std::array<T, Columns>, Rows> const& mat) {
std::array<T, Columns> sum;
((sum[Sizes] = m_col_add_impl2<Sizes>(std::make_index_sequence<Rows>(), mat)), ...);
return sum;
}
template <typename T, size_t Rows, size_t Columns>
std::array<T, Columns> m_col_add(std::array<std::array<T, Columns>, Rows> const& mat) {
return m_col_add_impl1(std::make_index_sequence<Columns>(), mat);
}
int main() {
std::array mat {
std::array {1, 2, 3, 4},
std::array {5, 6, 7, 8},
std::array {9, 10, 11, 12}
};
auto res = m_col_add(mat);
for (auto const& elem : res)
std::cout << elem << " ";
}
Output:
15 18 21 24
You could define operator+= for vectors which allows you to define a generalized Sum function that receives begin and end operators of a range to sum that works for iterators with any value type that works with the += operator like primitive types or (possibly nested) vectors of types that provide a += operator:
template<typename T>
std::vector<T>& operator+=(std::vector<T>& lhs, std::vector<T> const& rhs)
{
if (lhs.empty())
{
lhs = rhs; // first summand; 0 + x = x
}
else
{
for (size_t i = 0; i < lhs.size(); ++i)
{
lhs[i] += rhs.at(i); // component-wise add
}
}
return lhs;
}
// sum up elements in a given range
template<typename IteratorType>
typename std::iterator_traits<IteratorType>::value_type Sum(IteratorType summandBegin, IteratorType summandEnd)
{
typename std::iterator_traits<IteratorType>::value_type sum {}; // 0 or object created with default constructor depending on the type
while (summandBegin != summandEnd)
{
sum += *summandBegin;
++summandBegin;
}
return sum;
}
// sums the first count elements of a vector
template<typename T>
T PartialSum(std::vector<T> const& vec, size_t count)
{
assert(vec.size() >= count);
return Sum(vec.begin(), vec.begin() + count);
}
// logic for displaying
template<typename T>
std::ostream& operator<<(std::ostream& s, std::vector<T> const& vec)
{
s << '{';
for (auto& val : vec)
{
s << val << ", ";
}
s << '}';
return s;
}
int main(int argc, char *argv[]) {
std::vector<std::vector<std::vector<int>>> matrix { {{1, 2},{ 3, 4},{ 5, 6}},{{7, 8},{ 9, 10},{11, 12}},{{13, 14},{ 15, 16},{ 17, 18}}};
auto partialSum = PartialSum(matrix, 2);
std::cout << matrix << '\n' << partialSum << '\n';
std::cout << "\nSomething extra:\n";
std::vector<std::vector<std::string>> m2 = {{"Hell" , "Wo"} , {"o ", "rld!"}, {"foo", "bar"}};
auto message = PartialSum(m2, 2);
for (auto& msg : message)
{
std::cout << msg;
}
std::cout << '\n';
return 0;
}

Create a vector with repeated entries of each Element

I want to expand a given vector by repeating every entry three times. For example, if the vector is [5,7]. The output vector should be [5 5 5 7 7 7]
#include<iostream.h>
#include<vector.h>
int main(void)
{
std::vector<int> x;
x.push_back(5);
x.push_back(7);
x.insert(x.end(), x.begin(), x.begin() + 1);
return 0;
}
This didnt work out. Any help would be appreciated.
A simple approach is to loop over the vector and create a new one:
std::vector<int> vec{5, 7};
// create a new vector
std::vector<int> new_vec;
new_vec.reserve(vec.size() * 3);
for (auto elem : vec) {
for (std::size_t i = 0; i < 3; ++i) {
new_vec.push_back(elem);
}
}
I don't know how simple code you want, but for example this works.
#include<iostream>
#include<vector>
int main(void)
{
std::vector<int> x;
x.push_back(5);
x.push_back(7);
for (std::vector<int>::iterator it = x.end(); it != x.begin(); )
{
it--;
it = x.insert(it, 2, *it);
}
// print the vector to check
for (size_t i = 0; i < x.size(); i++) std::cout << x[i] << " ";
std::cout << std::endl;
return 0;
}
Maybe something like this could help you achieve that:
#include <iostream>
#include <algorithm>
#include <vector>
template<typename T>
std::vector<T> RepeateEntryNumberOfTimes(std::vector<T> input, std::uint16_t numberOfTimes)
{
std::vector<T> result;
std::for_each(input.begin(), input.end(), [&result, numberOfTimes](T item){
for(std::uint16_t numberOfReps = 0; numberOfReps != numberOfTimes; ++numberOfReps)
{
result.push_back(item);
}
});
return result;
}
See godbolt example: https://godbolt.org/z/ns9o3b
Your code has problem since it inserting elements to same vector.
Modification of vector invalidates old iterators, so your code has undefined behavior.
Even ignoring this error, logic of your code doesn't seem to do what you are expecting.
template<typename In, typename Out>
Out replicate_elements(In b, In e, size_t n, Out o)
{
while(b != e) {
o = std::fill_n(o, n, *b++);
}
return o;
}
std::vector<int> foo(const std::vector<int>& x)
{
std::vector<int> r;
r.reserve(x.size() * 3);
replicate_elements(x.begin(), x.end(), 3, std::back_inserter(r));
return r;
}
https://www.godbolt.org/z/zvE5TG

Finding multiple max elements in a vector C++

So.. I am trying to find the maximum value of a vector and its position in the vector. I am using a for loop, and it's working fine. My problem is, that if the maximum value appears more than once, I want to know all the positions in which it appears in the vector.. So, how could I manage this?
So far, this is the code I am using: (the vector called v has elements that I read from a file but I will not add that part of the code)
std::vector<double>v;
double maxvalue;
int position=0;
maxvalue = v[0];
for (unsigned int i=0; i<v.size(); i++){
if (v[i]> maxvalue){
maxvalue=v[i];
position= i;
}
}
You could modify your approach to keep a vector of indices where the maximum occurred:
#include <cfloat>
#include <iostream>
#include <utility>
#include <vector>
std::pair<double, std::vector<std::size_t>> FindMaxElements(std::vector<double> const& v)
{
std::vector<std::size_t> indices;
double current_max = -DBL_MAX;
for (std::size_t i = 0; i < v.size(); ++i)
{
if (v[i] > current_max)
{
current_max = v[i];
indices.clear();
}
if (v[i] == current_max)
{
indices.push_back(i);
}
}
return std::make_pair(current_max, indices);
}
int main()
{
auto result = FindMaxElements({1, 4, 7, 2, 7, 3});
std::cout << "max: " << result.first << '\n';
std::cout << "indices: ";
for (auto i : result.second)
std::cout << i << ' ';
}
Output
max: 7
indices: 2 4
Here is a two-pass version using the standard library (whereas it might be cleaner without it):
#include <vector>
#include <algorithm>
int main()
{
std::vector<double> v {/* fill it*/ };
std::vector<int> pos;
auto it = std::max_element(std::begin(v), std::end(v));
while (it != std::end(v))
{
pos.push_back(std::distance(std::begin(v), it));
it = std::find(std::next(it), std::end(v), *it);
}
//...
}
The function template below, find_maximums(), returns an std::vector<size_t> that contains the positions where the maximums are in the input vector. Note that it returns an empty vector of indexes if the input vector is empty.
template<typename T>
auto find_maximums(const std::vector<T>& v) {
std::vector<size_t> indexes;
for (auto it_max = std::max_element(v.begin(), v.end()); it_max != v.end();
it_max = std::find(it_max+1, v.end(), *it_max))
{
auto index = std::distance(v.begin(), it_max);
indexes.push_back(index);
}
return indexes;
}
As an example of use:
auto main() -> int {
std::vector<int> v = {11, 7, 3, 11, 0, 7, 1, 11, 11};
auto max_indexes = find_maximums(v);
if (max_indexes.empty())
return 1;
std::cout << "max: " << v[max_indexes.front()] << std::endl;
std::cout << "max at positions: ";
for (auto idx: max_indexes)
std::cout << idx << ' ';
std::cout << '\n';
}
It outputs:
max: 11
max at positions: 0 3 7 8
Passing a couple of iterators and a comparator
template <class It,
class Comp = std::less<typename std::iterator_traits<It>::value_type>>
auto max_elements_indices(It first, It last, Comp cmp = Comp{})
{
// This function returns a vector of indices, so to get the maximum, the caller
// should first check if the returned vector is empty and then use one of
// those indices to retrieve the value.
std::vector<std::size_t> indices;
if (first == last)
return indices;
// Using the first element instead of a sentinel value is easier to generalize
indices.push_back(0);
auto value = *first;
for (auto i = std::next(first); i != last; ++i)
{
// The most common case should be an element below the maximum
if ( cmp(*i, value) )
continue;
else
{
if ( cmp(value, *i) )
{
value = *i;
indices.clear();
}
indices.push_back(std::distance(first, i));
}
}
return indices;
}
It is testable here.

How to Subtract the first element in a vector from another first element in another vector?

I have 2 vectors of ints.
say the first one has (2,1).
and the second one (1,1).
I am trying to subtract numbers like this:
2 - 1,
1 - 1
then I need to add these 2 numbers so the final answer would be 1.
I've tried a for loop, but it's subtracting each number from each element, instead of only the first one.
This is what I've tried so far.
vector<int> temp;
for(unsigned i =0; i < Vec1.size(); i++)
for(unsigned o =0; o < Vec2.size(); o++)
temp.push_back(Vec1.at(i).nums- Vec2.at(o).nums);
//where nums, are just the numbers showed above
The output as you would expect is :
1
1
0
0
and I need it to be:
1
0
then I can just do a for loop to add all the ints together.
Any help, would be greatly appreciated!
I've tried a for loop, but it's subtracting each number from each element, instead of only the first one.
You are not doing it the right way. You have been using cascaded for loops and hence, you are subtracting each element of first vector from each element of second vector.
There are two ways to correctly implement:
One involves writing your own functions to subtract two vector and then adding elements of the result.
#include <iostream>
#include <vector>
std::vector<int> subtract(const std::vector<int>& a, const std::vector<int>& b)
{
std::vector<int> result;
const int SIZE = std::min(a.size(), b.size());
for (int i = 0; i < SIZE; i++)
result.push_back(a[i] - b[i]);
return result;
}
int addAllElements(const std::vector<int>& a)
{
int result = 0;
for (auto i: a)
result += i;
return result;
}
int main(void)
{
std::vector<int> a = {2, 1};
std::vector<int> b = {1, 1};
std::cout << "Result is " << addAllElements(subtract(a, b)) << std::endl;
return 0;
}
The other method (preferred) involves using STL:
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
int main(void)
{
std::vector<int> a = { 2, 1 };
std::vector<int> b = { 1, 1 };
std::vector<int> result;
std::transform(std::begin(a), std::end(a), std::begin(b), std::back_inserter(result), [](const auto a, const auto b)
{
return a - b;
}
);
int sumAllElements = std::accumulate(result.begin(), result.end(), 0);
std::cout << "Result is " << sumAllElements << std::endl;
return 0;
}
The above code uses lambda expression. To know more about them, see this link.
std::accumulate sums all the elements of the container and std::transform performs the transformation (specified in it's fifth argument) on two vectors and put the result in a different vector. We have used lambda expression to perform the required sub operation.
EDIT:
To implement it without lambda is also easy. You can use function pointers.
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
double subtract(const double a, const double b)
{
return a - b;
}
int main(void)
{
std::vector<int> a = { 2, 1 };
std::vector<int> b = { 1, 1 };
std::vector<int> result;
std::transform(std::begin(a), std::end(a), std::begin(b), std::back_inserter(result), subtract);
int sumAllElements = std::accumulate(result.begin(), result.end(), 0);
std::cout << "Result is " << sumAllElements << std::endl;
return 0;
}
There are various advantages of using lambda expression.
NOTE:
You can also use std::minus instead of defining you own function. Like this:
std::transform(std::begin(a), std::end(a), std::begin(b), std::back_inserter(result), std::minus<int>());
In C++17, you can combine std::transform and std::reduce/std::accumulate calls with std::transform_reduce:
const std::vector<int> vec1 {2, 1};
const std::vector<int> vec2 {1, 1};
auto res = std::transform_reduce(vec1.begin(), vec1.end(),
vec2.begin(),
0,
std::plus<>(),
std::minus<>());
Demo
Here is an example using the STL:
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
int main() {
std::vector<int> vec1 {2, 1};
std::vector<int> vec2 {1, 1};
std::vector<int> temp;
std::transform(begin(vec1), std::end(vec1), std::begin(vec2),
std::back_inserter(temp), [](const auto a, const auto b) {return a - b;});
auto sum = std::accumulate(temp.begin(), temp.end(), 0);
std::cout << "Result: " << sum << "\n";
return 0;
}

How to add all numbers in an array in C++?

Instead of typing
array[0] + array[1] //.....(and so on)
is there a way to add up all the numbers in an array? The language I'm using would be c++
I want to be able to do it with less typing than I would if I just typed it all out.
Here is the idiomatic way of doing this in C++:
int a[] = {1, 3, 5, 7, 9};
int total = accumulate(begin(a), end(a), 0, plus<int>());
Note, this example assumes you have somewhere:
#include <numeric>
using namespace std;
Also see: accumulate docs and accumulate demo.
Say you have an int array[N].
You can simply do:
int sum = 0;
for(auto& num : array)
sum += num;
Try this:
int array[] = {3, 2, 1, 4};
int sum = 0;
for (int i = 0; i < 4; i++) {
sum = sum + array[i];
}
std::cout << sum << std::endl;
If you use a valarray, there is a member function sum() for that.
#include <iostream> // std::cout
#include <valarray> // std::valarray
int main () {
std::valarray<int> myvalarray(4);
myvalarray[0] = 0;
myvalarray[1] = 10;
myvalarray[2] = 20;
myvalarray[3] = 30;
std::cout << "The sum is " << myvalarray.sum() << '\n';
return 0;
}
The easiest way I can see to do this is to use a loop. The bonus is that you can use it on any integer array without rewriting much code at all. I use Java more often, so I hope there aren't too many syntax errors, but something like this should work:
int addArray(int[] array, int length){
int sum=0;
for(int count=0;count<length;count++){
sum+=array[count];
}
return sum;
}
In C++17, one could use fold expressions:
template<typename ...Ts>
int sum_impl(Ts&& ...a)
{
return (a + ...);
}
If sum_impl had a constant number of parameters, we could have called it like this:
std::apply(sum_impl, arr);
assuming arr is std::array<int, N>. But since it is variadic, it needs a little push with helpers:
using namespace std;
template <class Array, size_t... I>
int sum_impl(Array&& a, index_sequence<I...>)
{
return sum_impl(get<I>(forward<Array>(a))...);
}
template <class Array>
int sum(Array&& a)
{
return sum_impl(forward<Array>(a),
make_index_sequence<tuple_size_v<decay_t<Array>>>{});
}
Therefore, assuming these helpers are in place, the code will look something like this:
template<typename ...Ts>
int sum_impl(Ts&& ...a)
{
return (a + ...);
}
int main()
{
array<int, 10> arr{0,1,2,3,4,5,6,7,8,9};
cout << sum(arr) << "\n";
return 0;
}
We may use user defined function.
Code Snippet :
#include<bits/stdc++.h>
using namespace std;
int sum(int arr[], int n)
{
int sum=0;
for(int i=0; i<n; i++)
{
sum += arr[i];
}
return sum;
}
int main()
{
int arr[] = {1, 2, 3, 4, 5};
int n = distance(begin(arr), end(arr));
int total = sum(arr,n);
printf("%d", total);
return 0;
}
int Sum;
for(int& S: List) Sum += S;
If your compiler supports c++17, you may use a combination of Parameter pack and fold expression to achieve this. A template parameter pack is a template parameter that accepts zero or more template arguments, and fold reduces the parameter pack over a binary operator. (+ in this case)
#include <iostream>
#include <array>
#include <utility>
/*
* References:
* [1] https://en.cppreference.com/w/cpp/language/fold
* [2] https://en.cppreference.com/w/cpp/language/parameter_pack
*/
template <typename ...T>
auto sum(T ...args)
{
return (args + ...);
}
template <typename T, std::size_t ...Is>
auto sum(T t, std::index_sequence<Is...>)
{
return sum(t[Is]...);
}
int main()
{
std::array<int, 3> a1 = {1, 4, 3};
int a2[5] = {1, 2, 3, 4, 0};
std::cout << "Sum a1 = " << sum(a1, std::make_index_sequence<a1.size()>{}) << "\n";
std::cout << "Sum a2 = " << sum(a2, std::make_index_sequence<5>{}) << "\n";
return 0;
}
Adding one more point regarding std::accumulate usage:
When a C-style array is passed to a function then you should explicitly specify the array start and end(one-past-the-end) addresses when you use the std::accumulate.
Example:
#include <numeric>
void outsideFun(int arr[], int n) {
int sz = sizeof arr / sizeof arr[0]; // 1=decays to a ptr to the 1st element of the arr
// int sum = accumulate(begin(arr), end(arr), 0); // Error:begin/end wouldn't work here
int sum = accumulate(arr, arr + n, 0); // 15 (Method 2 Only works!)
std::cout << sum;
}
int main() {
int arr[] = { 1,2,3,4,5 };
int sz = sizeof arr / sizeof arr[0]; // 5
int sum = accumulate(begin(arr), end(arr), 0); // 15 (Method 1 - works)
int cum = accumulate(arr, arr + sz, 0); // 15 (Method 2 - works)
outsideFun(arr, sz);
}