How to Sort a Std::Vector by the Values of a Different Std::Vector

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



Leave a reply



Submit