0

Suppose I have code such as the following, to sort elements of a data structure in another data structure, but keep a record of their original indices:

std::vector<int> numbers = {..};
std::vector<std::pair<int, std::vector<int>::size_type>> temp;

for (std::vector<int>::size_type i = 0; i < numbers.size(); i++)
{
    temp.push_back({ numbers[i], i });
}

std::sort(temp.begin(), temp.end(), [](const auto& x, const auto& y) { return x.first < y.first; });

So far so good. But what I really want is to store the data and indices in different data structures:

std::vector<int> sorted;
std::vector<std::vector<int>::size_type> indices;

Such that the element at sorted[i] was at index indices[i] in the original data structure.

Other than rolling out my own sorting algorithm, or splitting the data structure after the fact, is there any easy trick using the standard library to do this?

Neil Kirk
  • 21,327
  • 9
  • 53
  • 91

2 Answers2

0

The idea is to store your data in one container and have other containers with indices (based on different sorting criteria).

The idea here is to write function objects that compare two indices based on the sorting criteria and the value in the data container.

The next step is to pass your function object to the appropriate sorting function.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
0

Clarifying Thomas Matthew answer ... Create a vectors of indices 0 to n-1. Use a lambda function to sort the vector of indices according to the data vector. Example code including an optional reorder in place function.

void reorder(std::vector<int>& vA, std::vector<size_t> vI);

int main()
{
    std::vector <int> vdata = { 7,2,4,5,3,1,6,0 };      // original data
    std::vector <size_t> vindex = { 0,1,2,3,4,5,6,7 };  // original indices

    std::sort(vindex.begin(), vindex.end(), [&vdata](size_t i, size_t j)
        {return vdata[i] < vdata[j];});

    for (size_t i = 0; i < vdata.size(); i++)
        std::cout << "[" << vindex[i] << "]=" << vdata[vindex[i]] << " ";
    std::cout << std::endl;
    reorder(vdata, vindex);
    for (size_t i = 0; i < vdata.size(); i++)
        std::cout << "[" << i << "]=" << vdata[i] << " ";
    return 0;
}

// every move places an element in it's final location
// vI passed by value (copy)
void reorder(std::vector<int>& vA, std::vector<size_t> vI)
{
    size_t i, j, k;
    int tA;
    for (i = 0; i < vA.size(); i++) {
        if (i != vI[i]) {
            tA = vA[i];
            k = i;
            while (i != (j = vI[k])) {
                vA[k] = vA[j];
                vI[k] = k;
                k = j;
            }
            vA[k] = tA;
            vI[k] = k;
        }
    }
}
rcgldr
  • 27,407
  • 3
  • 36
  • 61