I want to find both the minimum and maximum of a long vector. The following code works, but I need to traverse the vector twice.
I could use an old fashioned for loop, but I wonder if there is an elegant (c++11, std) way of doing it.
#include <vector>
#include <algorithm>
using namespace std;
int main(int argc, char** argv) {
vector<double> C;
// code to insert values in C not shown here
const double cLower = *min_element(C.begin(), C.end());
const double cUpper = *max_element(C.begin(), C.end());
// code using cLower and cUpper
}
You mean like std::minmax_element?
auto mm = std::minmax_element(std::begin(c), std::end(c));
const double cLower = *mm.first;
const double cUpper = *mm.second;
Note this assumes the range is not empty (as does your existing solution), else the iterator dereferences are Undefined Behaviour.
Also note this is not quite the same as your solution, as max_element returns the first largest element, and minmax_element returns the last largest element. E.g.
1 2 1 2
^ ^
A B
Where A is found by your solution, and B is found by mine. (This is for reasons of stability; Alex Stepanov got the definition of max wrong in the original STL.)
Related
Is there a way to apply non-modifying standard library algorithms to discrete functions instead of containers?
For example, consider the following function
int sqr(int i)
{
return i*i;
}
How can I use std::find or std::lower_bound to search for the value 49, i.e. the algorithm should return 7? The easiest way would be to put the returns into a vector and apply the algorithm to the vector -- but this is obviously inefficient.
Hypothetically, you could use something like boost::iterator::counting_iterator. E.g., the following finds that 4 is the number whose square is 16:
#include <algorithm>
#include <iostream>
#include <boost/iterator/counting_iterator.hpp>
using namespace std;
int main(int, char**)
{
auto f = std::find_if(
boost::make_counting_iterator<int>(0),
boost::make_counting_iterator<int>(20),
[](int i){return i * i == 16;});
cout << std::distance(
boost::make_counting_iterator<int>(0),
f) << endl;
return 0;
}
I think that this approach is problematic in many ways. In the above, in particular, note that it searches for such numbers up to 20.
I have a vector of pairs of int, and I want to add all the first elements of each pair. I have written following code
#include <iostream>
#include <numeric>
#include <vector>
#include <utility>
#define PII pair<int,int>
using namespace std;
int main() {
vector<pair<int,int>> v;
v.push_back(PII(1,2));
v.push_back(PII(3,4));
v.push_back(PII(5,6));
cout<<accumulate(v.begin(),v.end(),0,[](auto &a, auto &b){return a.first+b.first;});
return 0;
}
Here it is giving errors http://ideone.com/Kf2i7d.
The required answer is 1+3+5 = 9. I can't understand the errors it is giving.
In this call of the algorithm
cout<<accumulate(v.begin(),v.end(),0,[](auto &a, auto &b){return a.first+b.first;});
its third parameter is initialized by 0 and hence has deduced type int.
It corresponds to the accumulator of the algorithm that accumulates the values that are suplied by the second parameter of the lambda expression.
So you have to write
cout<<accumulate(v.begin(),v.end(),0,[](auto &a, auto &b){return a + b.first;});
As for me I would initialize it with integer literal of type long long int. For example
cout<<accumulate(v.begin(),v.end(),0ll,[](auto &a, auto &b){return a +b.first;});
std::accumulate iterates over each element and calls the supplied function with the current element and the current value of the accumulator.
The accumulator has type int, not pair<int, int> so you need to fix your lambda function to accept the right argument types.
Chances are this is a very stupid question but I spent a pretty absurd amount of time looking for it on the documentation, to no avail.
in MATLAB, the find() function gives me an array with the indices of nonzero elements. Numpy's np.nonzero function does something similar.
How do I do this in the C++ Eigen library? I have a Boolean array of
typedef <bool, 10, 1> foobar = MatrixA < MatrixB;
so far. Thanks!
Not sure if this is part of your question, but to construct the appropriate element-wise inequality result you must first cast your matrices to arrays:
MatrixXd A,B;
...
Matrix<bool,Dynamic,Dynamic> C = A.array()<B.array();
Now C is the same size as A and B and C(i,j) = A(i,j) < B(i,j).
To find all of the indices (assuming column-major order) of the true entries, you can use this compact c++11 routine---as described by libigl's conversion table:
VectorXi I = VectorXi::LinSpaced(C.size(),0,C.size()-1);
I.conservativeResize(std::stable_partition(
I.data(), I.data()+I.size(), [&C](int i){return C(i);})-I.data());
Now I is C.nonZeros() long and contains indices of the true entries in C. These two lines essentially implement find.
It is reasonable to expect Eigen to have a find() function. Unfortunately, Eigen doesn't have one, or even a less than operator for matrices. Fortunately, the problem isn't too difficult. Here is one solution to the problem. I am using vector to store the Column Major indices of elements > 0. You could use VectorXf if you prefer that. Use this on B - A (B-A > 0 is the same as evaluating B>A). I'm using the stl for_each() function.
#include<algorithm>
#include<vector>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
class isGreater{
public:
vector<int>* GT;
isGreater(vector<int> *g){GT = g;}
void operator()(float i){static int it = 0; if(i>0)GT->push_back(it); it++;}
};
int main(int argc,char **argv){
MatrixXf P = MatrixXf::Random(4,5);
vector<int> GT;
for_each(P.data(),P.data()+P.rows()*P.cols(),isGreater(>));
cout<<P<<endl;
for(int i=0;i<GT.size();++i)cout<<GT[i]<<" ";
cout<<GT.size()<<endl;
return 0;
}
This might work for you and others who check this out. In order to set elements of a matrix m based on the condition on another matrix A, you can use this notation:
m = (A.array() != 0).select(1, m);
This command replaces those elements in matrix m that have non-zero corresponding elements in A, with one.
The program below (well, the lines after "from here") is a construct i have to use a lot.
I was wondering whether it is possible (eventually using functions from the eigen library)
to vectorize or otherwise make this program run faster.
Essentially, given a vector of float x, this construct has recover the indexes
of the sorted elements of x in a int vector SIndex. For example, if the first
entry of SIndex is 10, it means that the 10th element of x was the smallest element
of x.
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <vector>
using std::vector;
using namespace std;
typedef pair<int, float> sortData;
bool sortDataLess(const sortData& left, const sortData& right){
return left.second<right.second;
}
int main(){
int n=20,i;
float LO=-1.0,HI=1.0;
srand (time(NULL));
vector<float> x(n);
vector<float> y(n);
vector<int> SIndex(n);
vector<sortData> foo(n);
for(i=0;i<n;i++) x[i]=LO+(float)rand()/((float)RAND_MAX/(HI-LO));
//from here:
for(i=0;i<n;i++) foo[i]=sortData(i,x[i]);
sort(foo.begin(),foo.end(),sortDataLess);
for(i=0;i<n;i++){
sortData bar=foo[i];
y[i]=x[bar.first];
SIndex[i]=bar.first;
}
for(i=0;i<n;i++) std::cout << SIndex[i] << std::endl;
return 0;
}
There's no getting around the fact that this is a sorting problem, and vectorization doesn't necessarily improve sorts very much. For example, the partition step of quicksort can do the comparison in parallel, but it then needs to select and store the 0–n values that passed the comparison. This can absolutely be done, but it starts throwing out the advantages you get from vectorization—you need to convert from a comparison mask to a shuffle mask, which is probably a lookup table (bad), and you need a variable-sized store, which means no alignment (bad, although maybe not that bad). Mergesort needs to merge two sorted lists, which in some cases could be improved by vectorization, but in the worst case (I think) needs the same number of steps as the scalar case.
And, of course, there's a decent chance that any major speed boost you get from vectorization will have already been done inside your standard library's std::sort implementation. To get it, though, you'd need to be sorting primitive types with the default comparison operator.
If you're worried about performance, you can easily avoid the last loop, though. Just sort a list of indices using your float array as a comparison:
struct IndirectLess {
template <typename T>
IndirectLess(T iter) : values(&*iter) {}
bool operator()(int left, int right)
{
return values[left] < values[right];
}
float const* values;
};
int main() {
// ...
std::vector<int> SIndex;
SIndex.reserve(n);
for (int i = 0; i < n; ++i)
SIndex.push_back(n);
std::sort(SIndex.begin(), SIndex.end(), IndirectLess(x.begin()));
// ...
}
Now you've only produced your list of sorted indices. You have the potential to lose some cache locality, so for really big lists it might be slower. At that point it might be possible to vectorize your last loop, depending on the architecture. It's just data manipulation, though—read four values, store 1st and 3rd in one place and 2nd and 4th in another—so I wouldn't expect Eigen to help much at that point.
I'm trying to send a vector as an argument to a function and i can't figure out how to make it work. Tried a bunch of different ways but they all give different error messages.
I only include part of the code, since it's only this part that doesn't work.
(the vector "random" is filled with random, but sorted, values between 0 and 200)
Updated the code:
#include <iostream>
#include <ctime>
#include <algorithm>
#include <vector>
using namespace std;
int binarySearch(int first, int last, int search4, vector<int>& random);
int main()
{
vector<int> random(100);
int search4, found;
int first = 0;
int last = 99;
found = binarySearch(first, last, search4, random);
system("pause");
return(0);
}
int binarySearch(int first, int last, int search4, vector<int>& random)
{
do
{
int mid = (first + last) / 2;
if (search4 > random[mid])
first = mid + 1;
else if (search4 < random[mid])
last = mid - 1;
else
return mid;
} while (first <= last);
return -(first + 1);
}
It depends on if you want to pass the vector as a reference or as a pointer (I am disregarding the option of passing it by value as clearly undesirable).
As a reference:
int binarySearch(int first, int last, int search4, vector<int>& random);
vector<int> random(100);
// ...
found = binarySearch(first, last, search4, random);
As a pointer:
int binarySearch(int first, int last, int search4, vector<int>* random);
vector<int> random(100);
// ...
found = binarySearch(first, last, search4, &random);
Inside binarySearch, you will need to use . or -> to access the members of random correspondingly.
Issues with your current code
binarySearch expects a vector<int>*, but you pass in a vector<int> (missing a & before random)
You do not dereference the pointer inside binarySearch before using it (for example, random[mid] should be (*random)[mid]
You are missing using namespace std; after the <include>s
The values you assign to first and last are wrong (should be 0 and 99 instead of random[0] and random[99]
You'll have to pass the pointer to the vector, not the vector itself. Note the additional '&' here:
found = binarySearch(first, last, search4, &random);
You're passing in a pointer *random but you're using it like a reference &random
The pointer (what you have) says "This is the address in memory that contains the address of random"
The reference says "This is the address of random"
Anytime you're tempted to pass a collection (or pointer or reference to one) to a function, ask yourself whether you couldn't pass a couple of iterators instead. Chances are that by doing so, you'll make your function more versatile (e.g., make it trivial to work with data in another type of container when/if needed).
In this case, of course, there's not much point since the standard library already has perfectly good binary searching, but when/if you write something that's not already there, being able to use it on different types of containers is often quite handy.
found = binarySearch(first, last, search4, &random);
Notice the &.
You're using the argument as a reference but actually it's a pointer. Change vector<int>* to vector<int>&. And you should really set search4 to something before using it.
If you use random instead of * random your code not give any error