C++, Sort One Vector Based On Another One
As already suggested in other answers: Combining the name and the score of each individual is likely the simplest solution.
Generically, this can be achieved with what is sometimes referred to as a "zip" operation: Combining two vectors into a vector of pairs - along with a corresponding "unzip".
Implemented generically, this may look as follows:
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
// Fill the zipped vector with pairs consisting of the
// corresponding elements of a and b. (This assumes
// that the vectors have equal length)
template <typename A, typename B>
void zip(
const std::vector<A> &a,
const std::vector<B> &b,
std::vector<std::pair<A,B>> &zipped)
{
for(size_t i=0; i<a.size(); ++i)
{
zipped.push_back(std::make_pair(a[i], b[i]));
}
}
// Write the first and second element of the pairs in
// the given zipped vector into a and b. (This assumes
// that the vectors have equal length)
template <typename A, typename B>
void unzip(
const std::vector<std::pair<A, B>> &zipped,
std::vector<A> &a,
std::vector<B> &b)
{
for(size_t i=0; i<a.size(); i++)
{
a[i] = zipped[i].first;
b[i] = zipped[i].second;
}
}
int main(int argc, char* argv[])
{
std::vector<std::string> names {"Karl", "Martin", "Paul", "Jennie"};
std::vector<int> score {45, 5, 14, 24};
// Zip the vectors together
std::vector<std::pair<std::string,int>> zipped;
zip(names, score, zipped);
// Sort the vector of pairs
std::sort(std::begin(zipped), std::end(zipped),
[&](const auto& a, const auto& b)
{
return a.second > b.second;
});
// Write the sorted pairs back to the original vectors
unzip(zipped, names, score);
for(size_t i=0; i<names.size(); i++)
{
std::cout << names[i] << " : " << score[i] << std::endl;
}
return 0;
}
How do I sort a std::vector by the values of a different std::vector?
friol's approach is good when coupled with yours. First, build a vector consisting of the numbers 1…n, along with the elements from the vector dictating the sorting order:
typedef vector<int>::const_iterator myiter;
vector<pair<size_t, myiter> > order(Index.size());
size_t n = 0;
for (myiter it = Index.begin(); it != Index.end(); ++it, ++n)
order[n] = make_pair(n, it);
Now you can sort this array using a custom sorter:
struct ordering {
bool operator ()(pair<size_t, myiter> const& a, pair<size_t, myiter> const& b) {
return *(a.second) < *(b.second);
}
};
sort(order.begin(), order.end(), ordering());
Now you've captured the order of rearrangement inside order
(more precisely, in the first component of the items). You can now use this ordering to sort your other vectors. There's probably a very clever in-place variant running in the same time, but until someone else comes up with it, here's one variant that isn't in-place. It uses order
as a look-up table for the new index of each element.
template <typename T>
vector<T> sort_from_ref(
vector<T> const& in,
vector<pair<size_t, myiter> > const& reference
) {
vector<T> ret(in.size());
size_t const size = in.size();
for (size_t i = 0; i < size; ++i)
ret[i] = in[reference[i].first];
return ret;
}
Sorting a vector using values in another vector
You can make a third vector of indexes and sort that indirectly. After it's sorted, you can access the original vector through the sorted indexes:
std::vector<Foo> foo_vec = /* ... */;
std::vector<int> x_vec = /* ... */;
std::vector<std::size_t> index_vec;
assert(foo_vec.size() == x_vec.size());
for (std::size_t i = 0; i != foo_vec.size(); ++i) { index_vec.push_back(i); }
std::sort(
index_vec.begin(), index_vec.end(),
[&](std::size_t a, std::size_t b) { return x_vec[a] < x_vec[b]; });
for (std::size_t i = 0; i != index_vec.size(); ++i)
{
std::cout << "Sorted element " << i << " is "
<< foo_vec[index_vec[i]] << "\n";
}
Note that this operation is entirely non-invasive, since everything happens indirectly.
Sort a 3D std::vector based on values in a 1D std::vector
If your goal is to sort the scores and maintain the sorted scores with their relative position in the 3D vector, as the comment suggested and based on this answer, you can sort an array of indices that are based on the score
criteria.
After sorting the indices, you use the indices to "point to" each sorted item in the 3D vector.
Here is an example:
#include <algorithm>
#include <vector>
#include <numeric>
int main()
{
std::vector<std::vector<std::vector<char>>> children;
std::vector<int> score;
//...
// Assume score and children have values
//...
// Sort the 3D vector based on the scores
// Set up the index vector
std::vector<int> index(score.size());
std::iota(index.begin(), index.end(), 0);
//...
// sort the indices based on the scores
std::sort(index.begin(), index.end(), [&](int n1, int n2)
{ return score[n1] < score[n2]; });
//...
// Do something with the "sorted" 3D vector
// The first sorted child is children[index[0]], the second is children[index[1]], etc.
}
Note that the linked answer has a thorough explanation of why and when this technique is used.
How to sort any vector by value?
My guess is that you want to sort the vector by absolute value.
You can sort a vector with std::sort
in any way you want by passing a lambda to it.
The absolute value of an integer can be calulated using std::abs
.
std::sort(std::begin(vec), std::end(vec),
[](const auto& lhs, const auto& rhs){
return std::abs(lhs) < std::abs(rhs);
});
Sorting one vector with respect to another - most efficient way?
One common way is to create an index and sort it, rather than sorting the original values. This is known as indirect sort or argsort.
Example:
using values_t = std::vector<float>;
using index_t = std::vector<uint8_t>;
index_t make_sorted_index(values_t const& values) {
index_t index(values.size());
std::iota(index.begin(), index.end(), 0);
std::sort(index.begin(), index.end(), [&values](uint8_t a, uint8_t b) { return values[a] > values[b]; } );
return index;
}
int main() {
values_t a = {2,4,3,1};
values_t b = {1,2,3,4};
auto index = make_sorted_index(a);
std::cout << "A = {";
for(auto i : index)
std::cout << a[i] << ',';
std::cout << "\b}\n";
std::cout << "B = {";
for(auto i : index)
std::cout << b[i] << ',';
std::cout << "\b}\n";
}
Outputs:
A = {4,3,2,1}
B = {2,3,1,4}
Related Topics
Why Does Cout Print Char Arrays Differently from Other Arrays
Capturing Function Exit Time With _Gnu_Mcount_Nc
Difference Between Static and Shared Libraries
Range Based Loop: Get Item by Value or Reference to Const
Why Should the Copy Constructor Accept Its Parameter by Reference in C++
Which Iomanip Manipulators Are 'Sticky'
How to Make a Fully Statically Linked .Exe With Visual Studio Express 2005
What Are the Mechanics of Short String Optimization in Libc++
How to Create a Dynamic Array of Integers
In C++ Books, Array Bound Must Be Constant Expression, But Why the Following Code Works
Function Passed as Template Argument
Debugging With Command-Line Parameters in Visual Studio
Passing Object by Reference to Std::Thread in C++11
Array Placement-New Requires Unspecified Overhead in the Buffer
Sfinae Working in Return Type But Not as Template Parameter
Declaring Pointers; Asterisk on the Left or Right of the Space Between the Type and Name