I'm basing my question off the answer to this one:
How to obtain the index permutation after the sorting
I have two std::vectors:
std::vector<int> time={5, 16, 4, 7};
std::vector<int> amplitude={10,17,8,16};
I want to order the vectors for increasing time, so eventually they will be:
TimeOrdered={4,5,7,16};
AmplitudeOrdered={8,10,16,17};
Once finished, I want to add both ordered vectors to a CERN ROOT TTree. I looked online for solutions and found the example above, where the top answer is to use the following code:
vector<int> data = {5, 16, 4, 7};
vector<int> index(data.size(), 0);
for (int i = 0 ; i != index.size() ; i++) {
index[i] = i;
}
sort(index.begin(), index.end(),[&](const int& a, const int& b) {
return (data[a] < data[b]);
}
);
for (int ii = 0 ; ii != index.size() ; ii++) {
cout << index[ii] << endl;
}
Which I like because it's simple, it doesn't require too many lines and it leaves me with two simple vectors, which I can then use easily for my TTree.
I tried, therefore, to generalise it:
void TwoVectorSort(){
std::vector<int> data={5, 16, 4, 7};
std::vector<int> data2={10,17,8,16};
sort(data2.begin(), data2.end(),[&](const int& a, const int& b) {
return (data[a] < data[b]);
}
);
for (int ii = 0 ; ii != data2.size() ; ii++) {
std::cout <<data[ii]<<"\t"<< data2[ii]<<"\t"<< std::endl;//<<index[ii]
}
}
But not only does it not work, it gives me something different each time. I'm running it as a macro with ROOT 6.18/04, using .x TwoVectorSort.cpp+.
Can anyone tell me why it doesn't work and what the simplest solution is? I'm by no means a c++ expert so I hope the answers won't be too technical!
Thanks in advance!
Indeed you can re-use the solution from the link you shared to solve your problem. But you need to keep building the index
vector (and I believe there's no need to modify the time
or amplitude
vectors).
The index
vector is used to store the index/position of the time
vector values sorted from smallest to largest, so for time={5, 16, 4, 7}
:
index[0]
will contain the index of the smallest value fromtime
(which is4
, at position 2), henceindex[0]=2
index[1]
will contain the index of the 2nd smallest value fromtime
(which is5
, at position 0), henceindex[1]=0
etc.
And since amplitude
's order is based on time
you can use index[pos]
to access both vectors when building your tree:
time[index[pos]]
andamplitude[index[pos]]
Code with the corrections:
#include <iostream>
#include <vector>
#include <algorithm>
int main(){
std::vector<int> time={5, 16, 4, 7};
std::vector<int> amplitude={10,17,8,16};
std::vector<int> index(time.size(), 0);
for (int i = 0 ; i != index.size() ; i++) {
index[i] = i;
}
sort(index.begin(), index.end(),
[&](const int& a, const int& b) {
return (time[a] < time[b]);
}
);
std::cout << "Time \t Ampl \t idx" << std::endl;
for (int ii = 0 ; ii != index.size() ; ++ii) {
std::cout << time[index[ii]] << " \t " << amplitude[index[ii]] << " \t " << index[ii] << std::endl;
}
}
Output:
Time Ampl idx
4 8 2
5 10 0
7 16 3
16 17 1
But not only does it not work, it gives me something different each time
That happened because the parameters that the lambda was receiving were from data2={10,17,8,16}
and those values were being used as index to access the data
vector at return (data[a] < data[b])
. It caused some random sorting because it was accessing out of the vector's range and reading garbage from memory (hence the random behavior).