C++ Multiplying elements in a vector - c++

I have been looking for a more optimal solution to the following and I cannot seem to find one.
Let's say I have a vector:
std::vector<double> vars = {1, 2, 3}
I want to perform 1 * 2 * 3 I know that I can do the following:
int multi = 1;
for(int i = 0; (i < vars.size()-1); i++)
{
multi *= vars[i];
}
But, is there a more "C++11" way to do this? I really wanted to do this using lambda and so that I can calculate the multiply (product) of the vector without having another function inside the class, I'd rather have it calculated inside the function.

Yes, as usual, there is an algorithm (though this one's in <numeric>), std::accumulate (live example):
using std::begin;
using std::end;
auto multi = std::accumulate(begin(vars), end(vars), 1, std::multiplies<double>());
std::multiplies is in <functional>, too. By default, std::accumulate uses std::plus, which adds two values given to operator(). std::multiplies is a functor that multiplies them instead.
In C++14, you can replace std::multiplies<double> with std::multiplies<>, whose operator() is templated and will figure out the type. Based on what I've seen with Eric Niebler's Ranges proposal, it could possibly later look like vars | accumulate(1, std::multiplies<>()), but take that with a grain of salt.

You can use a ranged based for loop like:
std::vector<double> vars = {1, 2, 3}
int multi = 1;
for (const auto& e: vars)
multi *= e;

Another way is using inclusive_scan (C++17 and above)
The advantage is you can get multiplies of first "N" elements in a vector.
Below is the code. Explanation in comments.
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
int main()
{
//INPUT VECTOR
std::vector<int> data{ 3, 1, 4, 1, 5, 9, 2, 6 };
//OUTPUT VECTOR WITH MULTIPLIES
//FIRST ELEMENT - 3
//SECOND ELEMENT - 3 * 1
//THIRD ELEMENT - 3 * 1 * 4
//FOURTH ELEMENT - 3 * 1 * 4 * 1
// ..
// ..
//LAST ELEMENT - 3 * 1 * 4 * 1 * 5 * 9 * 2 * 6
std::vector<int> multiplies(data.size());
//Multiply all numbers in given vector.
inclusive_scan(data.begin(), data.end(),
multiplies.begin(),
std::multiplies<>{});
//PRODUCT OF FIRST 5 ELEMENTS.
std::cout << "Product of first 5 elements :: " << multiplies[4] << std::endl;
//PRODUCT OF ALL ELEMENTS
std::cout << "Product of all elements :: " << multiplies[data.size() - 1] << std::endl;
}
Also there is an overload where the execution policy can be specified.
Sequential execution or Parallel execution. Need to include "execution" header.
//MULTIPLY ALL NUMBERS IN VECTOR WITH PARALLEL EXECUTION.
inclusive_scan(std::execution::par,data.begin(), data.end(),
multiplies.begin(),
std::multiplies<>{});

Related

Sorting pairs of elements from vectors to maximize a function

I am working on a vector sorting algorithm for my personal particle physics studies but I am very new to coding.
Going through individual scenarios (specific vector sizes and combinations) by brute force becomes extremely chaotic for greater numbers of net vector elements, especially since this whole code will be looped up to 1e5 times.
Take four vectors of 'flavors' A and B: A+, A-, B+, and B-. I need to find two total pairs of elements such that some value k(V+, V-) is maximized with the restriction that different flavors cannot be combined! (V is just a flavor placeholder)
For example:
A+ = {a1+}
A- = {a1-}
B+ = {b1+, b2+}
B- = {b1-}
Since A+ and A- only have one element each, the value k(A+, A-) -> k(a1+, a1-). But for flavor B, there are two possible combinations.
k(b1+, b1-) OR k(b2+, b1-)
I would like to ensure that the combination of elements with the greater value of k is retained. As I said previously, this specific example is not TOO bad by brute force, but say B+ and B- had two elements each? The possible values would be:
k(b1+, b1-) or k(b2+,b2-) or k(b1+, b2-) or k(b2+, b1-)
where only one of these is correct. Furthermore, say two of those four B+B- combinations had greater k than that of A+A-. This would also be valid!
Any help would be appreciated!!! I can clarify if anything above is overly confusing!
I tried something like this,
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
static bool sortbypair(const pair<double, double> &a, const pair<double, double> &b)
{
return (k(a.first, a.second) > k(b.first, b.second)) && k(a.first, b.second) < k(a.second, b.first);
}
But I can't flesh it out.
If I understand your question correctly,
you have a function k which maps two doubles (or a std::pair<double, double>) to a single double. I am assuming double, it wasn't clear from the question. It also isn't strictly at the core of your problem.
you have four std::vector<double>s: aplus, aminus, bplus and bminus.
Your domain are all std::pair<double, double>s that you can form by combining the elements in aplus and aminus as well as all combinations from bplus and bminus respectively.
you want to either
find the pair in your domain that maximizes k
get a collection of all pairs in your domain, sorted by the value of k
Did I get this right? You state in your question
I need to find two total pairs of elements such that some value k(V+, V-) is maximized [...]
which confuses me a bit.
My suggestion is to break down your problem into three subtasks:
Create a range of all combinations of elements in the vectors Vplus and Vminus. This is often denoted as a cartesian product Vplus x Vminus.
Concatenate the ranges created in step 1 for aplus x aminus and bplus x bminus to get a range of all viable pairs in your domain.
Maximize/sort the range from step 2.
Implementation using range-v3
The range-v3 library provides some very convenient tools for this kind of task. Let's assume your k function looks like this:
double k(double x, double y) { return x*x + y*y; }
and your vectors look like this:
std::vector<double> ap{0., 4., 2., 3., 1.};
std::vector<double> am{2., -1.};
std::vector<double> bp{1., 0.5};
std::vector<double> bm{-1., 2.};
Let's define a range representing our domain:
using namespace ranges;
auto pairs_view = view::concat(
view::cartesian_product(ap, am),
view::cartesian_product(bp, bm)
);
The pairs_view instance doesn't actually create the pairs anywhere in memory. It is just an adaptor object that let's you iterate over all pairs that you can construct in the specified way. The pairs are created "lazily" on the fly as you - or an algorithm - iterates over it.
Let's print all pairs from our domain:
auto print = [](auto const& p){
auto first = std::get<0>(p);
auto second = std::get<1>(p);
std::cout << "[" << first << ", " << second << "] k = " << k(first, second) << std::endl;
};
for_each(pairs_view, print);
Output:
[0, 2] k = 4
[0, -1] k = 1
[4, 2] k = 20
[4, -1] k = 17
[2, 2] k = 8
[2, -1] k = 5
[3, 2] k = 13
[3, -1] k = 10
[1, 2] k = 5
[1, -1] k = 2
[1, -1] k = 2
[1, 2] k = 5
[0.5, -1] k = 1.25
[0.5, 2] k = 4.25
Finding the maximum element
Let's start by defining a convenience function (here, in the form of a lambda expression) that evaluates k for a tuple of doubles:
auto k_proj = [](auto const& p){
return k(std::get<0>(p), std::get<1>(p));
};
You can find an iterator to the pair in your domain that maximizes k with just the single line:
auto it = max_element(pairs_view, less{}, k_proj);
print(*it);
Output:
[4, 2] k = 20
The function max_element gets two additional arguments. The first is a comparison function that returns true, if two elements are in order. We provide the default less functor. The second argument is an optional projection that is to be applied on each element before the comparison. We pass k_proj.
Read the above line of code as "Find the element in pairs_view of which the projection onto its k value is maximal, where we want to compare the projected values with the standard less function."
Getting a sorted range of your domain
If you want to have all sorted range of all pairs in your domain, we must create an std::vector<std::pair<double, double>> for your domain first and then sort it. You cannot sort views created with the range-v3 library, because they are just a view into existing objects, they cannot be mutated. In addition, we have to map the special pair types created by the range-v3 library in the cartesian_product functions to actual std::pair<double, double to copy the values into our new container:
auto to_std_pair = [](auto const& p){
return std::pair<double, double>{std::get<0>(p), std::get<1>(p)};
};
auto pairs_vec = pairs_view | view::transform(to_std_pair) | to_vector;
Note that the "pipe" operator | is short-hand notation for the function composition to_vector(view::transform(pairs_view, to_std_pair)).
The invokation of the sorting algorithm looks very similar to the invokation of the max_element algorithm:
sort(pairs_vec, less{}, k_proj);
Let's print the result:
for_each(pairs_vec, print);
Output:
[0, -1] k = 1
[0.5, -1] k = 1.25
[1, -1] k = 2
[1, -1] k = 2
[0, 2] k = 4
[0.5, 2] k = 4.25
[2, -1] k = 5
[1, 2] k = 5
[1, 2] k = 5
[2, 2] k = 8
[3, -1] k = 10
[3, 2] k = 13
[4, -1] k = 17
[4, 2] k = 20
Here is a complete live code example: https://godbolt.org/z/6zo8oj3ah
If you don't want to use the range-v3 library you have two options:
You can wait. Large parts of the range-v3 library have been added to the standard library in C++20. The relevant functions concat, cartesian_product and to_vector will presumably be added in the upcoming standard C++23.
The standard library has max_element and sort. So you could just implement the concatenation and cartesian product on your own: https://godbolt.org/z/7Y5dG16WK
Thank you to everyone who commented!!! I really appreciate your effort. The solution ended up being much simpler than I was making it out to be.
Essentially, from the physics program I'm using, the particles are given in a listed form (ie. 533 e-, 534
p+, 535 e+, etc.). I couldn't figure out how to get range-v3 working (or any external libraries for that matter but thank you for the suggestion) so I figured out to make a tuple out of the indices of combined particles and their associated k value.
#include <iostream>
#include <vector>
#include <algorithm>
#include <tuple>
using namespace std;
static bool weirdsort(const tuple<int, int, double> &a, const tuple<int, int, double> &b)
{
return get<2>(a) > get<2>(b);
}
int main()
{
vector<tuple<int, int, double>> net;
// Sample ptcl list
//
// A+ A- B+ B-
// 0 a1+
// 1 a1-
// 2 b1-
// 3 b1+
// 4 a2+
// 5 a2-
for(int i = 0; i < A+.size(); i++)
{
for (int j = 0; j < A-.size(); j++)
{
net.push_back(A+[i], A-[j], k(A+[i], A-[j]));
}
}
sort(net.begin(), net.end(), weirdsort);
//Now another for loop that erases a tuple (with a lower k value) if it has a repeated ptcl index.
for (int i = 0; i < net.size(); i++)
{
if (get<0>(net[i]) == get<0>(net[i + 1]) || get<1>(net[i]) == get<1>(net[i + 1]))
{
net.erase(net.begin() + i + 1);
}
}
//Now can plot third tuple element of net[0] and net[1]
return 0;
}
It's not quite perfect but since I'm only looking for the first two highest k values it works out just fine. Thanks again!

Can you access the current iterator from a function used by the transform function in c++?

Can you access the current iterator from a function used by the transform function in c++ so that you can reference previous and latter values?
I want to use the transform function to iterate through a vector, performing operations on the vector that rely on values before and after the current value.
For example, say I have a vector with values [1,2,4,3,5,6], and I want to start at the second value, and iterate until the second to last value. On each of those elements, I want to make a new value that equals the sum of the value, and the values next to it in the original.
The ending vector would look like
[7,9,12,14].
auto originalsBeginIterator = originalPoints.begin();
auto originalsEndIterator = originalPoints.end();
std::advance(originalsBeginIterator, 1);
std::advance(originalsEndIterator,-1);
std::transform(originalsBeginIterator,originalsEndIterator,alteredValues.begin(),
[](int x) x = { return {previous value} + x + {next value};}
);
Is there any way to reference previous and latter values from the original array when using transform?
Clearly the tool std::transform simply doesn't give you a way to do that: it either takes a unary predicate to be applied to individual elements of of one collection, or a binary predicate to be applied to corresponding elements of two collections.
But the point is that, from the functional programming perspective, what you are trying to do is simply not a transform.
How can you go about it instead? You could zip that vector, let's call it v, the same vector deprived of its first element, and the same vector deprived from its second element; you would then sum the 3 elements of each pair.
Range-v3 gives you a way to do this quite tersely:
#include <iostream>
#include <range/v3/view/drop.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/view/zip_with.hpp>
#include <vector>
using namespace ranges::views;
int main()
{
// input
std::vector<int> v{1,2,3,4,5,6};
// to sum 3 ints
auto constexpr plus = [](int x, int y, int z){ return x + y + z; };
// one-liner
auto w = zip_with(plus, v, v | drop(1), v | drop(2));
// output
std::cout << w << std::endl;
}
v | drop(1) gives you a view on the elements {2,3,4,5,6}, and v | drop(2) on {3,4,5,6}; zip_with taks a n-ary function and n ranges and combines the n-tuple of corresponding elements from the n ranges using the n-ary function. So in our case it'll go like this:
v = {1, 2, 3, 4, 5, 6}
+ + + +
v1 = v | drop(1) = {2, 3, 4, 5, 6}
+ + + +
v2 = v | drop(2) = {3, 4, 5, 6}
zip_with(plus, v, v1, v2) = {6, 9,12,15}

Adjusting index in a vector in C++

I am writing a code in which the values of vector indexes are displayed as per the sorted order of the elements they hold:
For example:
values -> 3 2 4 1 5
indices -> 1 2 3 4 5 //yeah I know C++ indexing starts with 0. Well, while printing, I will add 1
result -> 4 2 1 3 5 //Bear with me. I know its confusing. I will clarify below
Now, the result has been obtained by sorting the elements and printing their earlier indices.
Like:
values(sorted) -> 1 2 3 4 5
indices(before sorting) -> 4 2 1 3 5
Now, there are many ways to do it with some suggesting to store the previous values and search and print the previous index, while others suggesting to create a new vector and copy the previous indices in it and then sorting them and.... (Well I didn't read further, 'cause that's definitely not how I was gonna proceed)
I tried a different approach while trying to not use a second vector.
So here's the approach:
while (!vec_students.empty()) {
std::vector<int>::iterator iterator = std::min_element(vec_students.begin(), vec_students.end());
std::cout << std::distance(vec_students.begin(), iterator) + 1 << " ";
vec_students.erase(iterator);
}
Now in this approach, the problem I am facing is that once I use erase, the index of all elements decreases by a certain incrementing value. So this was the solution I thought of:
while (!vec_students.empty()) {
static int i = 0; //yeah I know standard static variables are initialised to 1.
std::vector<int>::iterator iterator = std::min_element(vec_students.begin(), vec_students.end());
std::cout << std::distance(vec_students.begin(), iterator) + i << " ";
vec_students.erase(iterator);
i++;
}
Now the thought goes like this:
Initial Solution:
vector: 2 3 1
expected output: 3 1 2 (For explanation refer above)
first index = indexof(min(2,3,1)) -> 2 (while printing add 1) -> 3
second index = indexof(min(2,3)) -> 0 (while printing....) -> 1
third index = indexof(min(3)) -> 0 (while...) -> 1
Then I realized that the vector size decreases which means, indices will decrease (by 1 in this case)
so I added the extra i thingy.
Solution working:
vector: 2 3 1 i = 0
first index = indexof(min(2,3,1)) -> 3 -> add i -> 3 -> increment i -> i = 1
second index = indexof(min(2,3)) -> 0 -> add i -> 1 -> increment i -> i = 2
third index = indexof(min(3)) -> 0 -> add i -> 2 -> increment i -> i = 3
and the program ends.
But in the above case, instead of 3 1 2 I am getting 3 2 3 (first value right, rest incremented by 1)
What is wrong with my logic?
the index of all elements decreases by a certain incrementing value.
Not all, just the ones that come after the one you removed. Here's one way to do it without making another vector:
#include <algorithm>
#include <iostream>
#include <limits>
#include <vector>
int main() {
std::vector<int> v{3, 2, 4, 1, 5};
auto const* beg = v.data();
auto sz = v.size();
while (sz--) {
auto const min = std::min_element(v.begin(), v.end());
std::cout << &*min - beg << ' ';
*min = std::numeric_limits<int>::max();
}
}
This won't work properly if you have INT_MAX in your vector. In any case, making a second vector could yield better solutions. An example:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::vector<int> v{3, 2, 4, 1, 5};
std::vector<int const*> addresses;
addresses.reserve(v.size());
std::transform(v.cbegin(), v.cend(), std::back_inserter(addresses),
[](auto const& elm) { return &elm; });
std::sort(addresses.begin(), addresses.end(),
[](int const* const ptr1, int const* const ptr2) {
return *ptr1 < *ptr2;
});
for (auto* p : addresses) {
std::cout << p - v.data() << ' ';
}
}
You think you should add indices because the vector is shrink.
Well, not really, only those after the removed element should be effected.
example.
[2,1,3] => [2,3]
index of 2 remains at 0,
while index of 3 becomes 1 from 2

Swap the elements of two sequences, such that the difference of the element-sums gets minimal.

An interview question:
Given two non-ordered integer sequences a and b, their size is n, all
numbers are randomly chosen: Exchange the elements of a and b, such that the sum of the elements of a minus the sum of the elements of b is minimal.
Given the example:
a = [ 5 1 3 ]
b = [ 2 4 9 ]
The result is (1 + 2 + 3) - (4 + 5 + 9) = -12.
My algorithm: Sort them together and then put the first smallest n ints in a and left in b. It is O(n lg n) in time and O(n) in space. I do not know how to improve it to an algorithm with O(n) in time and O(1) in space. O(1) means that we do not need more extra space except seq 1 and 2 themselves.
Any ideas ?
An alternative question would be: What if we need to minimize the absolute value of the differences (minimize |sum(a) - sum(b)|)?
A python or C++ thinking is preferred.
Revised solution:
Merge both lists x = merge(a,b).
Calculate median of x (complexity O(n) See http://en.wikipedia.org/wiki/Selection_algorithm )
Using this median swap elements between a and b. That is, find an element in a that is less than median, find one in b that is more than median and swap them
Final complexity: O(n)
Minimizing absolute difference is NP complete since it is equivalent to the knapsack problem.
What comes into my mind is following algorithm outline:
C = A v B
Partitially sort #A (number of A) Elements of C
Subtract the sum of the last #B Elements from C from the sum of the first #A Elements from C.
You should notice, that you don't need to sort all elements, it is enough to find the number of A smallest elements. Your example given:
C = {5, 1, 3, 2, 4, 9}
C = {1, 2, 3, 5, 4, 9}
(1 + 2 + 3) - (5 + 4 + 9) = -12
A C++ solution:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
// Initialize 'a' and 'b'
int ai[] = { 5, 1, 3 };
int bi[] = { 2, 4, 9 };
std::vector<int> a(ai, ai + 3);
std::vector<int> b(bi, bi + 3);
// 'c' = 'a' merged with 'b'
std::vector<int> c;
c.insert(c.end(), a.begin(), a.end());
c.insert(c.end(), b.begin(), b.end());
// partitially sort #a elements of 'c'
std::partial_sort(c.begin(), c.begin() + a.size(), c.end());
// build the difference
int result = 0;
for (auto cit = c.begin(); cit != c.end(); ++cit)
result += (cit < c.begin() + a.size()) ? (*cit) : -(*cit);
// print result (and it's -12)
std::cout << result << std::endl;
}

Finding smallest values of given vectors

How can I find the smallest value of each column in the given set of vectors efficiently ?
For example, consider the following program:
#include <iostream>
#include <vector>
#include <iterator>
#include <cstdlib>
using namespace std;
typedef vector<double> v_t;
int main(){
v_t v1,v2,v3;
for (int i = 1; i<10; i++){
v1.push_back(rand()%10);
v2.push_back(rand()%10);
v3.push_back(rand()%10);
}
copy(v1.begin(), v1.end(), ostream_iterator<double>(cout, " "));
cout << endl;
copy(v2.begin(), v2.end(), ostream_iterator<double>(cout, " "));
cout << endl;
copy(v3.begin(), v3.end(), ostream_iterator<double>(cout, " "));
cout << endl;
}
Let the output be
3 5 6 1 0 6 2 8 2
6 3 2 2 9 0 6 7 0
7 5 9 7 3 6 1 9 2
In this program I want to find the smallest value of every column (of the 3 given vectors) and put it into a vector. In this program I want to define a vector v_t vfinal that will have the values :
3 3 2 1 0 0 1 7 0
Is there an efficient way to do this ? I mention efficient because my program may have to find the smallest values among very large number of vectors. Thank you.
Update:
I'm trying to use something like this which I used in one of my previous programs
int count = std::inner_product(A, A+5, B, 0, std::plus<int>(), std::less<int>());
This counts the number of minimum elements between two arrays A and B. Wouldn't it be efficient enough if I could loop through and use similar kind of function to find the minimal values ? I'm not claiming it can be done or not. It's just an idea that may be improved upon but I don't know how.
You can use std::transform for this. The loops are still there, they're just hidden inside the algorithm. Each additional vector to process is a call to std::transform.
This does your example problem in two linear passes.
typedef std::vector<double> v_t;
int main()
{
v_t v1,v2,v3,vfinal(9); // note: vfinal sized to accept results
for (int i = 1; i < 10; ++i) {
v1.push_back(rand() % 10);
v2.push_back(rand() % 10);
v3.push_back(rand() % 10);
}
std::transform(v1.begin(), v1.end(), v2.begin(), vfinal.begin(), std::min<double>);
std::transform(v3.begin(), v3.end(), vfinal.begin(), vfinal.begin(), std::min<double>);
}
Note: this works in MSVC++ 2010. I had to provide a min functor for gcc 4.3.
I think that the lower bound of your problem is O(n*m), where n is the number of vectors and m the elements of each vector.
The trivial algorithm (comparing the elements at the same index of the different vectors) is as efficient as it can be, I think.
The easiest way to implement it would be to put all your vectors in some data structure (a simple C-like array, or maybe a vector of vectors).
The bst way to do this would be to use a vector of vectors, and just simple looping.
void find_mins(const std::vector<std::vector<int> >& inputs, std::vector<int>& outputs)
{
// Assuming that each vector is the same size, resize the output vector to
// change the size of the output vector to hold enough.
output.resize(inputs[0].size());
for (std::size_t i = 0; i < inputs.size(); ++i)
{
int min = inputs[i][0];
for (std::size_t j = 1; j < inputs[i].size(); ++j)
if (inputs[i][j] < min) min = inputs[i][j];
outputs[i] = min;
}
}
To find the smallest number in a vector, you simply have to examine each element in turn; there's no quicker way, at least from an algorithmic point-of-view.
In terms of practical performance, cache issues may affect you here. As has been mentioned in a comment, it will probably be more cache-efficient if you could store your vectors column-wise rather than row-wise. Alternatively, you may want to do all min searches in parallel, so as to minimise cache misses. i.e. rather than this:
foreach (col)
{
foreach (row)
{
x_min[col] = std::min(x_min[col], x[col][row]);
}
}
you should probably do this:
foreach (row)
{
foreach (col)
{
x_min[col] = std::min(x_min[col], x[col][row]);
}
}
Note that STL already provides a nice function to do this: min_element().