Search code examples
c++sortingc++20

Is there a way to sort a single member variable in a collection of structs using the C++ standard library?


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.


Solution

  • 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}
    

    Demo

    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.