Let's say I have a vector of a very simple struct:
struct SimpleStruct { int a; int b; int c; };
std::vector<SimpleStruct> vs;
I wish to sort this struct by 'a' leaving the positions of 'b' and 'c' unchanged. Essentially pivoting on a
, sorting by a
, and then unpivoting. As an example:
before: {1, 10, 11}, { 5, 100, 111}, {3, 1000, 1111}
after: {1, 10, 11}, {3, 100, 111}, {5, 1000, 1111} //'a' is now sorted, 'b' and 'c' relative position unchanged
If I only cared about correctness and wanted to minimize the amount of potential errors, using the standard library, the obvious solution is to create a second collection of type {value, index}, sort by value, and then overwrite the value at the corresponding index.
This is incredibly inefficient, since conceptually all we really need is a standard sorting operation with a custom comparison and a custom swap.
Is there a way to do this in C++ using the standard library without creating a custom sort method?
C++20 preferred, preferably without the use of Ranges.
This can be done easily with the help of C++20 ranges
std::vector<SimpleStruct> vs = {{1, 10, 11}, {5, 100, 111}, {3, 1000, 1111}};
std::ranges::sort(vs | std::views::transform(&SimpleStruct::a));
// vs now becoms {1, 10, 11}, {3, 100, 111}, {5, 1000, 1111}
Note that ranges::sort(vs, {}, &SimpleStruct::a)
is incorrect as the projection is only applied to comparison, so it will still sort the entire SimpleStruct
object rather than SimpleStruct::a
.