For getting sorting indices in C++, one usually would not create a new vector with index-value pairs, but choose a comparator, which would achieve the same without actually copying memory.
Translating this to Cython would look as follows:
%%cython -+ -c=-std=c++11
from libcpp.vector cimport vector
cdef extern from *:
"""
#include <algorithm>
#include <vector>
void sort_via_score(std::vector<int>& indices, const std::vector<double>& scores){
std::sort(indices.begin(), indices.end(),
[&scores](int i, int j){return scores.at(i)<scores.at(j);}
);
}
"""
void sort_via_score(vector[int]& indices, vector[double]& scores)
def sort_indices(lst):
cdef vector[double] scores = lst
cdef vector[int] indices = range(len(lst))
sort_via_score(indices, scores)
return indices
The function sort_indices is a wrapper which allows us to check the implementation quickly:
sort_indices([5,4,3,2,1])
# [4, 3, 2, 1, 0] as expected
sort_via_score works similar to the following one-liner in Python:
def sort_indices_py(scores):
return sorted(range(len(scores)), key=lambda x: scores[x])
the scores-vector is used in the closure to look-up the score of the index . There are no new objects created which would put index and its score together in memory - they are combined by logic of the key-function alone.
The solution above uses verbatim C-code, because it is so much easier to write C++ code with C++ than with Cython.
If one really wants to stick to "pure" Cython (I don't recomend), so it is possible to emulate the C++-closures with the following code:
%%cython -+
from libcpp.vector cimport vector
from libcpp.algorithm cimport sort as stdsort
cdef vector[double]* vec
cdef bint comp_fun(int i, int j):
return vec.at(i)<vec.at(j)
def sort_indices2(lst):
cdef vector[double] scores = lst
cdef vector[int] indices = range(len(lst))
global vec
vec = &scores # "global closure"
stdsort(indices.begin(), indices.end(), comp_fun)
return indices