Related
Using C++, and hopefully the standard library, I want to sort a sequence of samples in ascending order, but I also want to remember the original indexes of the new samples.
For example, I have a set, or vector, or matrix of samples A : [5, 2, 1, 4, 3]. I want to sort these to be B : [1,2,3,4,5], but I also want to remember the original indexes of the values, so I can get another set which would be:
C : [2, 1, 4, 3, 0 ] - which corresponds to the index of each element in 'B', in the original 'A'.
For example, in Matlab you can do:
[a,b]=sort([5, 8, 7])
a = 5 7 8
b = 1 3 2
Can anyone see a good way to do this?
Using C++ 11 lambdas:
#include <iostream>
#include <vector>
#include <numeric> // std::iota
#include <algorithm> // std::sort, std::stable_sort
using namespace std;
template <typename T>
vector<size_t> sort_indexes(const vector<T> &v) {
// initialize original index locations
vector<size_t> idx(v.size());
iota(idx.begin(), idx.end(), 0);
// sort indexes based on comparing values in v
// using std::stable_sort instead of std::sort
// to avoid unnecessary index re-orderings
// when v contains elements of equal values
stable_sort(idx.begin(), idx.end(),
[&v](size_t i1, size_t i2) {return v[i1] < v[i2];});
return idx;
}
Now you can use the returned index vector in iterations such as
for (auto i: sort_indexes(v)) {
cout << v[i] << endl;
}
You can also choose to supply your original index vector, sort function, comparator, or automatically reorder v in the sort_indexes function using an extra vector.
You could sort std::pair instead of just ints - first int is original data, second int is original index. Then supply a comparator that only sorts on the first int. Example:
Your problem instance: v = [5 7 8]
New problem instance: v_prime = [<5,0>, <8,1>, <7,2>]
Sort the new problem instance using a comparator like:
typedef std::pair<int,int> mypair;
bool comparator ( const mypair& l, const mypair& r)
{ return l.first < r.first; }
// forgetting the syntax here but intent is clear enough
The result of std::sort on v_prime, using that comparator, should be:
v_prime = [<5,0>, <7,2>, <8,1>]
You can peel out the indices by walking the vector, grabbing .second from each std::pair.
Suppose Given vector is
A=[2,4,3]
Create a new vector
V=[0,1,2] // indicating positions
Sort V and while sorting instead of comparing elements of V , compare corresponding elements of A
//Assume A is a given vector with N elements
vector<int> V(N);
std::iota(V.begin(),V.end(),0); //Initializing
sort( V.begin(),V.end(), [&](int i,int j){return A[i]<A[j];} );
vector<pair<int,int> >a;
for (i = 0 ;i < n ; i++) {
// filling the original array
cin >> k;
a.push_back (make_pair (k,i)); // k = value, i = original index
}
sort (a.begin(),a.end());
for (i = 0 ; i < n ; i++){
cout << a[i].first << " " << a[i].second << "\n";
}
Now a contains both both our values and their respective indices in the sorted.
a[i].first = value at i'th.
a[i].second = idx in initial array.
I wrote generic version of index sort.
template <class RAIter, class Compare>
void argsort(RAIter iterBegin, RAIter iterEnd, Compare comp,
std::vector<size_t>& indexes) {
std::vector< std::pair<size_t,RAIter> > pv ;
pv.reserve(iterEnd - iterBegin) ;
RAIter iter ;
size_t k ;
for (iter = iterBegin, k = 0 ; iter != iterEnd ; iter++, k++) {
pv.push_back( std::pair<int,RAIter>(k,iter) ) ;
}
std::sort(pv.begin(), pv.end(),
[&comp](const std::pair<size_t,RAIter>& a, const std::pair<size_t,RAIter>& b) -> bool
{ return comp(*a.second, *b.second) ; }) ;
indexes.resize(pv.size()) ;
std::transform(pv.begin(), pv.end(), indexes.begin(),
[](const std::pair<size_t,RAIter>& a) -> size_t { return a.first ; }) ;
}
Usage is the same as that of std::sort except for an index container to receive sorted indexes.
testing:
int a[] = { 3, 1, 0, 4 } ;
std::vector<size_t> indexes ;
argsort(a, a + sizeof(a) / sizeof(a[0]), std::less<int>(), indexes) ;
for (size_t i : indexes) printf("%d\n", int(i)) ;
you should get 2 1 0 3.
for the compilers without c++0x support, replace the lamba expression as a class template:
template <class RAIter, class Compare>
class PairComp {
public:
Compare comp ;
PairComp(Compare comp_) : comp(comp_) {}
bool operator() (const std::pair<size_t,RAIter>& a,
const std::pair<size_t,RAIter>& b) const { return comp(*a.second, *b.second) ; }
} ;
and rewrite std::sort as
std::sort(pv.begin(), pv.end(), PairComp(comp)()) ;
I came across this question, and figured out sorting the iterators directly would be a way to sort the values and keep track of indices; There is no need to define an extra container of pairs of ( value, index ) which is helpful when the values are large objects; The iterators provides the access to both the value and the index:
/*
* a function object that allows to compare
* the iterators by the value they point to
*/
template < class RAIter, class Compare >
class IterSortComp
{
public:
IterSortComp ( Compare comp ): m_comp ( comp ) { }
inline bool operator( ) ( const RAIter & i, const RAIter & j ) const
{
return m_comp ( * i, * j );
}
private:
const Compare m_comp;
};
template <class INIter, class RAIter, class Compare>
void itersort ( INIter first, INIter last, std::vector < RAIter > & idx, Compare comp )
{
idx.resize ( std::distance ( first, last ) );
for ( typename std::vector < RAIter >::iterator j = idx.begin( ); first != last; ++ j, ++ first )
* j = first;
std::sort ( idx.begin( ), idx.end( ), IterSortComp< RAIter, Compare > ( comp ) );
}
as for the usage example:
std::vector < int > A ( n );
// populate A with some random values
std::generate ( A.begin( ), A.end( ), rand );
std::vector < std::vector < int >::const_iterator > idx;
itersort ( A.begin( ), A.end( ), idx, std::less < int > ( ) );
now, for example, the 5th smallest element in the sorted vector would have value **idx[ 5 ] and its index in the original vector would be distance( A.begin( ), *idx[ 5 ] ) or simply *idx[ 5 ] - A.begin( ).
Consider using std::multimap as suggested by #Ulrich Eckhardt. Just that the code could be made even simpler.
Given
std::vector<int> a = {5, 2, 1, 4, 3}; // a: 5 2 1 4 3
To sort in the mean time of insertion
std::multimap<int, std::size_t> mm;
for (std::size_t i = 0; i != a.size(); ++i)
mm.insert({a[i], i});
To retrieve values and original indices
std::vector<int> b;
std::vector<std::size_t> c;
for (const auto & kv : mm) {
b.push_back(kv.first); // b: 1 2 3 4 5
c.push_back(kv.second); // c: 2 1 4 3 0
}
The reason to prefer a std::multimap to a std::map is to allow equal values in original vectors. Also please note that, unlike for std::map, operator[] is not defined for std::multimap.
There is another way to solve this, using a map:
vector<double> v = {...}; // input data
map<double, unsigned> m; // mapping from value to its index
for (auto it = v.begin(); it != v.end(); ++it)
m[*it] = it - v.begin();
This will eradicate non-unique elements though. If that's not acceptable, use a multimap:
vector<double> v = {...}; // input data
multimap<double, unsigned> m; // mapping from value to its index
for (auto it = v.begin(); it != v.end(); ++it)
m.insert(make_pair(*it, it - v.begin()));
In order to output the indices, iterate over the map or multimap:
for (auto it = m.begin(); it != m.end(); ++it)
cout << it->second << endl;
Beautiful solution by #Lukasz Wiklendt! Although in my case I needed something more generic so I modified it a bit:
template <class RAIter, class Compare>
vector<size_t> argSort(RAIter first, RAIter last, Compare comp) {
vector<size_t> idx(last-first);
iota(idx.begin(), idx.end(), 0);
auto idxComp = [&first,comp](size_t i1, size_t i2) {
return comp(first[i1], first[i2]);
};
sort(idx.begin(), idx.end(), idxComp);
return idx;
}
Example: Find indices sorting a vector of strings by length, except for the first element which is a dummy.
vector<string> test = {"dummy", "a", "abc", "ab"};
auto comp = [](const string &a, const string& b) {
return a.length() > b.length();
};
const auto& beginIt = test.begin() + 1;
vector<size_t> ind = argSort(beginIt, test.end(), comp);
for(auto i : ind)
cout << beginIt[i] << endl;
prints:
abc
ab
a
Make a std::pair in function then sort pair :
generic version :
template< class RandomAccessIterator,class Compare >
auto sort2(RandomAccessIterator begin,RandomAccessIterator end,Compare cmp) ->
std::vector<std::pair<std::uint32_t,RandomAccessIterator>>
{
using valueType=typename std::iterator_traits<RandomAccessIterator>::value_type;
using Pair=std::pair<std::uint32_t,RandomAccessIterator>;
std::vector<Pair> index_pair;
index_pair.reserve(std::distance(begin,end));
for(uint32_t idx=0;begin!=end;++begin,++idx){
index_pair.push_back(Pair(idx,begin));
}
std::sort( index_pair.begin(),index_pair.end(),[&](const Pair& lhs,const Pair& rhs){
return cmp(*lhs.second,*rhs.second);
});
return index_pair;
}
ideone
Well, my solution uses residue technique. We can place the values under sorting in the upper 2 bytes and the indices of the elements - in the lower 2 bytes:
int myints[] = {32,71,12,45,26,80,53,33};
for (int i = 0; i < 8; i++)
myints[i] = myints[i]*(1 << 16) + i;
Then sort the array myints as usual:
std::vector<int> myvector(myints, myints+8);
sort(myvector.begin(), myvector.begin()+8, std::less<int>());
After that you can access the elements' indices via residuum. The following code prints the indices of the values sorted in the ascending order:
for (std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
std::cout << ' ' << (*it)%(1 << 16);
Of course, this technique works only for the relatively small values in the original array myints (i.e. those which can fit into upper 2 bytes of int). But it has additional benefit of distinguishing identical values of myints: their indices will be printed in the right order.
If it's possible, you can build the position array using find function, and then sort the array.
Or maybe you can use a map where the key would be the element, and the values a list of its position in the upcoming arrays (A, B and C)
It depends on later uses of those arrays.
I recently stepped upon the elegant projection feature of C++20 <ranges> and it allows to write shorter/clearer code:
std::vector<std::size_t> B(std::size(A));
std::iota(begin(B), end(B), 0);
std::ranges::sort(B, {}, [&](std::size_t i){ return A[i]; });
{} refers to the usual std::less<std::size_t>. So as you can see we define a function to call on each element before any comparaison. This projection feature is actually quite powerful since this function can be, as here, a lambda or it can even be a method, or a member value. For instance:
struct Item {
float price;
float weight;
float efficiency() const { return price / weight; }
};
int main() {
std::vector<Item> items{{7, 9}, {3, 4}, {5, 3}, {9, 7}};
std::ranges::sort(items, std::greater<>(), &Item::efficiency);
// now items are sorted by their efficiency in decreasing order:
// items = {{5, 3}, {9, 7}, {7, 9}, {3, 4}}
}
If we wanted to sort by increasing price:
std::ranges::sort(items, {}, &Item::price);
Don't define operator< or use lambdas, use a projection!
Are the items in the vector unique? If so, copy the vector, sort one of the copies with STL Sort then you can find which index each item had in the original vector.
If the vector is supposed to handle duplicate items, I think youre better of implementing your own sort routine.
For this type of question
Store the orignal array data into a new data and then binary search the first element of the sorted array into the duplicated array and that indice should be stored into a vector or array.
input array=>a
duplicate array=>b
vector=>c(Stores the indices(position) of the orignal array
Syntax:
for(i=0;i<n;i++)
c.push_back(binarysearch(b,n,a[i]));`
Here binarysearch is a function which takes the array,size of array,searching item and would return the position of the searched item
One solution is to use a 2D vector.
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<vector<double>> val_and_id;
val_and_id.resize(5);
for (int i = 0; i < 5; i++) {
val_and_id[i].resize(2); // one to store value, the other for index.
}
// Store value in dimension 1, and index in the other:
// say values are 5,4,7,1,3.
val_and_id[0][0] = 5.0;
val_and_id[1][0] = 4.0;
val_and_id[2][0] = 7.0;
val_and_id[3][0] = 1.0;
val_and_id[4][0] = 3.0;
val_and_id[0][1] = 0.0;
val_and_id[1][1] = 1.0;
val_and_id[2][1] = 2.0;
val_and_id[3][1] = 3.0;
val_and_id[4][1] = 4.0;
sort(val_and_id.begin(), val_and_id.end());
// display them:
cout << "Index \t" << "Value \n";
for (int i = 0; i < 5; i++) {
cout << val_and_id[i][1] << "\t" << val_and_id[i][0] << "\n";
}
return 0;
}
Here is the output:
Index Value
3 1
4 3
1 4
0 5
2 7
I have two index sets, one in the range [0, N], one in the range [0, M], where N != M. The indices are used to refer to values in different thrust::device_vectors.
Essentially, I want to create one GPU thread for every combination of these indices, so N*M threads. Each thread should compute a value based on the index-combination and store the result in another thrust::device_vector, at a unique index also based on the input combination.
This seems to be a fairly standard problem, but I was unable to find a way to do this in thrust. The documentation only ever mentions problems, where element i of a vector needs to compute something with element i of another vector. There is the thrust::permutation_iterator, but as far as I understand it only gives me the option to reorder data, and I have to specify the order as well.
Some code:
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <iostream>
int main()
{
// Initialize some data
const int N = 2;
const int M = 3;
thrust::host_vector<int> vec1_host(N);
thrust::host_vector<int> vec2_host(M);
vec1_host[0] = 1;
vec1_host[1] = 5;
vec2_host[0] = -3;
vec2_host[1] = 42;
vec2_host[2] = 9;
// Copy to device
thrust::device_vector<int> vec1_dev = vec1_host;
thrust::device_vector<int> vec2_dev = vec2_host;
// Allocate device memory to copy results to
thrust::device_vector<int> result_dev(vec1_host.size() * vec2_host.size());
// Create functor I want to call on every combination
struct myFunctor
{
thrust::device_vector<int> const& m_vec1;
thrust::device_vector<int> const& m_vec2;
thrust::device_vector<int>& m_result;
myFunctor(thrust::device_vector<int> const& vec1, thrust::device_vector<int> const& vec2, thrust::device_vector<int>& result)
: m_vec1(vec1), m_vec2(vec2), m_result(result)
{
}
__host__ __device__
void operator()(size_t i, size_t j) const
{
m_result[i + j * m_vec1.size()] = m_vec1[i] + m_vec1[j];
}
} func(vec1_dev, vec2_dev, result_dev);
// How do I create N*M threads, each of which calls func(i, j) ?
// Copy results back
thrust::host_vector<int> result_host = result_dev;
for(int i : result_host)
std::cout << i << ", ";
std::cout << std::endl;
// Expected output:
// -2, 2, 43, 47, 10, 14
return 0;
}
I'm fairly sure this is very easy to achieve, I guess I'm just missing the right search terms. Anyways, all help appreciated :)
Presumably in your functor operator instead of this:
m_result[i + j * m_vec1.size()] = m_vec1[i] + m_vec1[j];
^ ^
you meant this:
m_result[i + j * m_vec1.size()] = m_vec1[i] + m_vec2[j];
^ ^
I think there are probably many ways to tackle this, but so as to not argue about things that are not germane to the question, I'll try and stay as close to your given code as I can.
Operations like [] on a vector are not possible in device code. Therefore we must convert your functor to work on raw data pointers, rather than thrust vector operations directly.
With those caveats, and a slight modification in how we handle your i and j indices, I think what you're asking is not difficult.
The basic strategy is to create a result vector that is of length N*M just as you suggest, then create the indices i and j within the functor operator. In so doing, we need only pass one index to the functor, using e.g. thrust::transform or thrust::for_each to create our output:
$ cat t79.cu
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/for_each.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/execution_policy.h>
#include <iostream>
struct myFunctor
{
const int *m_vec1;
const int *m_vec2;
int *m_result;
size_t v1size;
myFunctor(thrust::device_vector<int> const& vec1, thrust::device_vector<int> const& vec2, thrust::device_vector<int>& result)
{
m_vec1 = thrust::raw_pointer_cast(vec1.data());
m_vec2 = thrust::raw_pointer_cast(vec2.data());
m_result = thrust::raw_pointer_cast(result.data());
v1size = vec1.size();
}
__host__ __device__
void operator()(const size_t x) const
{
size_t i = x%v1size;
size_t j = x/v1size;
m_result[i + j * v1size] = m_vec1[i] + m_vec2[j];
}
};
int main()
{
// Initialize some data
const int N = 2;
const int M = 3;
thrust::host_vector<int> vec1_host(N);
thrust::host_vector<int> vec2_host(M);
vec1_host[0] = 1;
vec1_host[1] = 5;
vec2_host[0] = -3;
vec2_host[1] = 42;
vec2_host[2] = 9;
// Copy to device
thrust::device_vector<int> vec1_dev = vec1_host;
thrust::device_vector<int> vec2_dev = vec2_host;
// Allocate device memory to copy results to
thrust::device_vector<int> result_dev(vec1_host.size() * vec2_host.size());
// How do I create N*M threads, each of which calls func(i, j) ?
thrust::for_each_n(thrust::device, thrust::counting_iterator<size_t>(0), (N*M), myFunctor(vec1_dev, vec2_dev, result_dev));
// Copy results back
thrust::host_vector<int> result_host = result_dev;
for(int i : result_host)
std::cout << i << ", ";
std::cout << std::endl;
// Expected output:
// -2, 2, 43, 47, 10, 14
return 0;
}
$ nvcc -std=c++11 -arch=sm_61 -o t79 t79.cu
$ ./t79
-2, 2, 43, 47, 10, 14,
$
In retrospect, I think this is more or less exactly what #eg0x20 was suggesting.
Using C++, and hopefully the standard library, I want to sort a sequence of samples in ascending order, but I also want to remember the original indexes of the new samples.
For example, I have a set, or vector, or matrix of samples A : [5, 2, 1, 4, 3]. I want to sort these to be B : [1,2,3,4,5], but I also want to remember the original indexes of the values, so I can get another set which would be:
C : [2, 1, 4, 3, 0 ] - which corresponds to the index of each element in 'B', in the original 'A'.
For example, in Matlab you can do:
[a,b]=sort([5, 8, 7])
a = 5 7 8
b = 1 3 2
Can anyone see a good way to do this?
Using C++ 11 lambdas:
#include <iostream>
#include <vector>
#include <numeric> // std::iota
#include <algorithm> // std::sort, std::stable_sort
using namespace std;
template <typename T>
vector<size_t> sort_indexes(const vector<T> &v) {
// initialize original index locations
vector<size_t> idx(v.size());
iota(idx.begin(), idx.end(), 0);
// sort indexes based on comparing values in v
// using std::stable_sort instead of std::sort
// to avoid unnecessary index re-orderings
// when v contains elements of equal values
stable_sort(idx.begin(), idx.end(),
[&v](size_t i1, size_t i2) {return v[i1] < v[i2];});
return idx;
}
Now you can use the returned index vector in iterations such as
for (auto i: sort_indexes(v)) {
cout << v[i] << endl;
}
You can also choose to supply your original index vector, sort function, comparator, or automatically reorder v in the sort_indexes function using an extra vector.
You could sort std::pair instead of just ints - first int is original data, second int is original index. Then supply a comparator that only sorts on the first int. Example:
Your problem instance: v = [5 7 8]
New problem instance: v_prime = [<5,0>, <8,1>, <7,2>]
Sort the new problem instance using a comparator like:
typedef std::pair<int,int> mypair;
bool comparator ( const mypair& l, const mypair& r)
{ return l.first < r.first; }
// forgetting the syntax here but intent is clear enough
The result of std::sort on v_prime, using that comparator, should be:
v_prime = [<5,0>, <7,2>, <8,1>]
You can peel out the indices by walking the vector, grabbing .second from each std::pair.
Suppose Given vector is
A=[2,4,3]
Create a new vector
V=[0,1,2] // indicating positions
Sort V and while sorting instead of comparing elements of V , compare corresponding elements of A
//Assume A is a given vector with N elements
vector<int> V(N);
std::iota(V.begin(),V.end(),0); //Initializing
sort( V.begin(),V.end(), [&](int i,int j){return A[i]<A[j];} );
vector<pair<int,int> >a;
for (i = 0 ;i < n ; i++) {
// filling the original array
cin >> k;
a.push_back (make_pair (k,i)); // k = value, i = original index
}
sort (a.begin(),a.end());
for (i = 0 ; i < n ; i++){
cout << a[i].first << " " << a[i].second << "\n";
}
Now a contains both both our values and their respective indices in the sorted.
a[i].first = value at i'th.
a[i].second = idx in initial array.
I wrote generic version of index sort.
template <class RAIter, class Compare>
void argsort(RAIter iterBegin, RAIter iterEnd, Compare comp,
std::vector<size_t>& indexes) {
std::vector< std::pair<size_t,RAIter> > pv ;
pv.reserve(iterEnd - iterBegin) ;
RAIter iter ;
size_t k ;
for (iter = iterBegin, k = 0 ; iter != iterEnd ; iter++, k++) {
pv.push_back( std::pair<int,RAIter>(k,iter) ) ;
}
std::sort(pv.begin(), pv.end(),
[&comp](const std::pair<size_t,RAIter>& a, const std::pair<size_t,RAIter>& b) -> bool
{ return comp(*a.second, *b.second) ; }) ;
indexes.resize(pv.size()) ;
std::transform(pv.begin(), pv.end(), indexes.begin(),
[](const std::pair<size_t,RAIter>& a) -> size_t { return a.first ; }) ;
}
Usage is the same as that of std::sort except for an index container to receive sorted indexes.
testing:
int a[] = { 3, 1, 0, 4 } ;
std::vector<size_t> indexes ;
argsort(a, a + sizeof(a) / sizeof(a[0]), std::less<int>(), indexes) ;
for (size_t i : indexes) printf("%d\n", int(i)) ;
you should get 2 1 0 3.
for the compilers without c++0x support, replace the lamba expression as a class template:
template <class RAIter, class Compare>
class PairComp {
public:
Compare comp ;
PairComp(Compare comp_) : comp(comp_) {}
bool operator() (const std::pair<size_t,RAIter>& a,
const std::pair<size_t,RAIter>& b) const { return comp(*a.second, *b.second) ; }
} ;
and rewrite std::sort as
std::sort(pv.begin(), pv.end(), PairComp(comp)()) ;
I came across this question, and figured out sorting the iterators directly would be a way to sort the values and keep track of indices; There is no need to define an extra container of pairs of ( value, index ) which is helpful when the values are large objects; The iterators provides the access to both the value and the index:
/*
* a function object that allows to compare
* the iterators by the value they point to
*/
template < class RAIter, class Compare >
class IterSortComp
{
public:
IterSortComp ( Compare comp ): m_comp ( comp ) { }
inline bool operator( ) ( const RAIter & i, const RAIter & j ) const
{
return m_comp ( * i, * j );
}
private:
const Compare m_comp;
};
template <class INIter, class RAIter, class Compare>
void itersort ( INIter first, INIter last, std::vector < RAIter > & idx, Compare comp )
{
idx.resize ( std::distance ( first, last ) );
for ( typename std::vector < RAIter >::iterator j = idx.begin( ); first != last; ++ j, ++ first )
* j = first;
std::sort ( idx.begin( ), idx.end( ), IterSortComp< RAIter, Compare > ( comp ) );
}
as for the usage example:
std::vector < int > A ( n );
// populate A with some random values
std::generate ( A.begin( ), A.end( ), rand );
std::vector < std::vector < int >::const_iterator > idx;
itersort ( A.begin( ), A.end( ), idx, std::less < int > ( ) );
now, for example, the 5th smallest element in the sorted vector would have value **idx[ 5 ] and its index in the original vector would be distance( A.begin( ), *idx[ 5 ] ) or simply *idx[ 5 ] - A.begin( ).
Consider using std::multimap as suggested by #Ulrich Eckhardt. Just that the code could be made even simpler.
Given
std::vector<int> a = {5, 2, 1, 4, 3}; // a: 5 2 1 4 3
To sort in the mean time of insertion
std::multimap<int, std::size_t> mm;
for (std::size_t i = 0; i != a.size(); ++i)
mm.insert({a[i], i});
To retrieve values and original indices
std::vector<int> b;
std::vector<std::size_t> c;
for (const auto & kv : mm) {
b.push_back(kv.first); // b: 1 2 3 4 5
c.push_back(kv.second); // c: 2 1 4 3 0
}
The reason to prefer a std::multimap to a std::map is to allow equal values in original vectors. Also please note that, unlike for std::map, operator[] is not defined for std::multimap.
There is another way to solve this, using a map:
vector<double> v = {...}; // input data
map<double, unsigned> m; // mapping from value to its index
for (auto it = v.begin(); it != v.end(); ++it)
m[*it] = it - v.begin();
This will eradicate non-unique elements though. If that's not acceptable, use a multimap:
vector<double> v = {...}; // input data
multimap<double, unsigned> m; // mapping from value to its index
for (auto it = v.begin(); it != v.end(); ++it)
m.insert(make_pair(*it, it - v.begin()));
In order to output the indices, iterate over the map or multimap:
for (auto it = m.begin(); it != m.end(); ++it)
cout << it->second << endl;
Beautiful solution by #Lukasz Wiklendt! Although in my case I needed something more generic so I modified it a bit:
template <class RAIter, class Compare>
vector<size_t> argSort(RAIter first, RAIter last, Compare comp) {
vector<size_t> idx(last-first);
iota(idx.begin(), idx.end(), 0);
auto idxComp = [&first,comp](size_t i1, size_t i2) {
return comp(first[i1], first[i2]);
};
sort(idx.begin(), idx.end(), idxComp);
return idx;
}
Example: Find indices sorting a vector of strings by length, except for the first element which is a dummy.
vector<string> test = {"dummy", "a", "abc", "ab"};
auto comp = [](const string &a, const string& b) {
return a.length() > b.length();
};
const auto& beginIt = test.begin() + 1;
vector<size_t> ind = argSort(beginIt, test.end(), comp);
for(auto i : ind)
cout << beginIt[i] << endl;
prints:
abc
ab
a
Make a std::pair in function then sort pair :
generic version :
template< class RandomAccessIterator,class Compare >
auto sort2(RandomAccessIterator begin,RandomAccessIterator end,Compare cmp) ->
std::vector<std::pair<std::uint32_t,RandomAccessIterator>>
{
using valueType=typename std::iterator_traits<RandomAccessIterator>::value_type;
using Pair=std::pair<std::uint32_t,RandomAccessIterator>;
std::vector<Pair> index_pair;
index_pair.reserve(std::distance(begin,end));
for(uint32_t idx=0;begin!=end;++begin,++idx){
index_pair.push_back(Pair(idx,begin));
}
std::sort( index_pair.begin(),index_pair.end(),[&](const Pair& lhs,const Pair& rhs){
return cmp(*lhs.second,*rhs.second);
});
return index_pair;
}
ideone
Well, my solution uses residue technique. We can place the values under sorting in the upper 2 bytes and the indices of the elements - in the lower 2 bytes:
int myints[] = {32,71,12,45,26,80,53,33};
for (int i = 0; i < 8; i++)
myints[i] = myints[i]*(1 << 16) + i;
Then sort the array myints as usual:
std::vector<int> myvector(myints, myints+8);
sort(myvector.begin(), myvector.begin()+8, std::less<int>());
After that you can access the elements' indices via residuum. The following code prints the indices of the values sorted in the ascending order:
for (std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)
std::cout << ' ' << (*it)%(1 << 16);
Of course, this technique works only for the relatively small values in the original array myints (i.e. those which can fit into upper 2 bytes of int). But it has additional benefit of distinguishing identical values of myints: their indices will be printed in the right order.
If it's possible, you can build the position array using find function, and then sort the array.
Or maybe you can use a map where the key would be the element, and the values a list of its position in the upcoming arrays (A, B and C)
It depends on later uses of those arrays.
I recently stepped upon the elegant projection feature of C++20 <ranges> and it allows to write shorter/clearer code:
std::vector<std::size_t> B(std::size(A));
std::iota(begin(B), end(B), 0);
std::ranges::sort(B, {}, [&](std::size_t i){ return A[i]; });
{} refers to the usual std::less<std::size_t>. So as you can see we define a function to call on each element before any comparaison. This projection feature is actually quite powerful since this function can be, as here, a lambda or it can even be a method, or a member value. For instance:
struct Item {
float price;
float weight;
float efficiency() const { return price / weight; }
};
int main() {
std::vector<Item> items{{7, 9}, {3, 4}, {5, 3}, {9, 7}};
std::ranges::sort(items, std::greater<>(), &Item::efficiency);
// now items are sorted by their efficiency in decreasing order:
// items = {{5, 3}, {9, 7}, {7, 9}, {3, 4}}
}
If we wanted to sort by increasing price:
std::ranges::sort(items, {}, &Item::price);
Don't define operator< or use lambdas, use a projection!
Are the items in the vector unique? If so, copy the vector, sort one of the copies with STL Sort then you can find which index each item had in the original vector.
If the vector is supposed to handle duplicate items, I think youre better of implementing your own sort routine.
For this type of question
Store the orignal array data into a new data and then binary search the first element of the sorted array into the duplicated array and that indice should be stored into a vector or array.
input array=>a
duplicate array=>b
vector=>c(Stores the indices(position) of the orignal array
Syntax:
for(i=0;i<n;i++)
c.push_back(binarysearch(b,n,a[i]));`
Here binarysearch is a function which takes the array,size of array,searching item and would return the position of the searched item
One solution is to use a 2D vector.
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<vector<double>> val_and_id;
val_and_id.resize(5);
for (int i = 0; i < 5; i++) {
val_and_id[i].resize(2); // one to store value, the other for index.
}
// Store value in dimension 1, and index in the other:
// say values are 5,4,7,1,3.
val_and_id[0][0] = 5.0;
val_and_id[1][0] = 4.0;
val_and_id[2][0] = 7.0;
val_and_id[3][0] = 1.0;
val_and_id[4][0] = 3.0;
val_and_id[0][1] = 0.0;
val_and_id[1][1] = 1.0;
val_and_id[2][1] = 2.0;
val_and_id[3][1] = 3.0;
val_and_id[4][1] = 4.0;
sort(val_and_id.begin(), val_and_id.end());
// display them:
cout << "Index \t" << "Value \n";
for (int i = 0; i < 5; i++) {
cout << val_and_id[i][1] << "\t" << val_and_id[i][0] << "\n";
}
return 0;
}
Here is the output:
Index Value
3 1
4 3
1 4
0 5
2 7
I'm having trouble getting my head around how to use inner_product to combine a std::vector<float> and a std::vector<std::vector<float>>. Given, e.g., <2,3> and <<4,5>,<6,7>>, I'd like inner_product to produce
2*<4,5> + 3*<6,7> = <8,10> + <18,21> = <26,31>.
Supposing
vector<float> foo;
and
vector<vector<float>> bar;
are initialized and are of equal size, I don't know what UK1, UK2, and UK3 in
vector<float> ip =
inner_product(foo.begin(), foo.end(), bar.begin(), UK1, UK2, UK3);
should be. I suspect UK1 should be a vector filled with 0.0fs, of the same size as the vectors in bar. UK3 should perhaps be something like
std::transform(UK4.begin(), UK4.end(), UK4.begin(),
std::bind1st(std::multiplies<float>(), UK5));
And I guess UK2 should somehow represent component-wise vector<float> addition!
I don't even want to think about how much more complex this will become when the vectors in bar are replaced by objects of a class with float attributes...
Define the add and multiply functions like this:
static vector<float> add(const vector<float> &a,const vector<float> &b)
{
assert(a.size()==b.size());
size_t n = a.size();
vector<float> result(n);
for (size_t i=0; i!=n; ++i) {
result[i] = a[i]+b[i];
}
return result;
}
static vector<float> mul(const float &a,const vector<float> &b)
{
size_t n = b.size();
vector<float> result = b;
for (size_t i=0; i!=n; ++i) {
result[i] *= a;
}
return result;
}
And use it like this:
vector<float> zero(2,0);
vector<float> result =
inner_product(a.begin(),a.end(),b.begin(),zero,add,mul);
std::inner_product accumulates a sum. UK2 is the sum operation. UK1 is normally the neutral element of UK2. UK3 is the multiplication operation that multiplies corresponding elements of the two sequences and returns a summand for UK2.
I guess std::valarray should provide a more suitable container for this operation.
// this is c++11
#include <vector>
#include <valarray>
#include <algorithm>
#include <iostream>
int main ()
{
std::valarray <int> zero = { 0, 0 };
std::vector <int> foo = { 1, 2, 3 };
std::vector <std::valarray<int>> bar = { { 3, 4 }, { 5, 6 }, { 7, 8 } };
std::valarray<int> result = std::inner_product (foo.begin(), foo.end(),
bar.begin(), zero);
for(auto n : result) {
std::cout << n << ' ';
}
std::cout << std::endl;
}
First, I'm sorry, I don't know a lot of c++, maybe my question is kind of stupid.
I have a multidimensional vector M. I want to be able to apply the same function either along the elements of a row i, or along the elements of a column j. I don't want to write the same function twice. It is possibly to do this in a rather simple way, like some overloading or with virtual iterators? can anyone write a simple example? thank you.
You can define you own iterator over the columns, so that you can use standard algorithms (like for_each, or transform as mentionned in another answer) to apply you function either to rows or columns of you array by just changing the iterators:
#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
// Custom iterator to iterate over columns
// to be adapted to the underlying storage
class ColIterator : public std::iterator<std::forward_iterator_tag, double>
{
public:
typedef std::vector<std::vector<double> > MDarray;
ColIterator(MDarray & array, int i, int j) : array_(array), i_(i), j_(j) {}
ColIterator(const ColIterator& it) : array_(it.array_), i_(it.i_), j_(it.j_) {}
ColIterator& operator++() {
++i_;
return *this;
}
ColIterator operator++(int) {
ColIterator tmp(*this);
operator++();
return tmp;
}
bool operator==(const ColIterator& rhs) { return &array_==&rhs.array_ && i_==rhs.i_ && j_==rhs.j_; }
bool operator!=(const ColIterator& rhs) { return !operator==(rhs); }
double& operator*() {return array_[i_][j_];}
private:
MDarray & array_;
int i_;
int j_;
};
// a function
void mult2 (double & x) {
x *= 2;
}
int main () {
typedef std::vector<double>::iterator RowIterator;
int nRows = 5;
int nCols = 5;
ColIterator::MDarray array (nRows, std::vector<double>(nCols, 1));
// Apply function mult2 to column 3
int col = 3;
ColIterator beginCol (array, 0, col);
ColIterator endCol (array, nRows, col);
std::for_each(beginCol, endCol, mult2);
// Apply function mult2 to row 4
int row = 4;
RowIterator beginRow (array[row].begin());
RowIterator endRow (array[row].end());
std::for_each(beginRow, endRow, mult2);
// Check results
for (int i=0 ; i<nRows ; ++i) {
for (int j=0 ; j<nCols ; ++j) {
std::cout << " " << array[i][j];
}
std::cout << std::endl;
}
return 0;
}
A good way to go about this would be to use std::transform. Consult this link for more details. Short example with how to do this for rows is below. The column part is a little tricky.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int nRowCnt = 3, nColCnt = 3;
int RowFunc(int i) { return ++i; }
int ColFunc(int i) { return --i; }
void PrintArray(vector<vector<int>>& vecArray, int nRowCnt, int nColCnt)
{
for (int nOuter = 0; nOuter < nRowCnt; nOuter++)
{
for (int nInner = 0; nInner < nColCnt; nInner++)
{
cout<<vecArray[nOuter][nInner]<<" ";
}
cout<<endl;
}
}
int main()
{
vector< vector<int> > vecVals(nRowCnt, vector<int>(nColCnt,0));
vector< int > rowOut(nColCnt*nRowCnt,0), colOut(nColCnt*nRowCnt,0);
vector<int>::iterator itrOut;
for (int nRow = 0; nRow < nRowCnt; nRow++)
{
for (int nCol = 0; nCol < nColCnt; nCol++)
{
vecVals[nRow][nCol] = nRow * (10+nCol) ;
}
}
PrintArray(vecVals,nRowCnt,nColCnt);
itrOut = rowOut.begin();
for (int nOuter = 0; nOuter < nRowCnt; nOuter++)
{
std::transform(vecVals[nOuter].begin(),vecVals[nOuter].end(),itrOut,RowFunc);
itrOut += nColCnt;
}
itrOut = colOut.begin();
for (int nOuter = 0; nOuter < nRowCnt; nOuter++)
{
for (int nInner = 0; nInner < nColCnt; nInner++)
{
std::transform( vecVals[nInner].begin() + nOuter, vecVals[nInner].begin() + nOuter +1, itrOut,ColFunc);
itrOut++;
}
}
cout<<endl<<"Row Transformed"<<endl;
for (itrOut = rowOut.begin(); itrOut != rowOut.end(); itrOut++)
cout<<*itrOut<<" ";
cout<<endl<<"Col Transformed"<<endl;
for (itrOut = colOut.begin(); itrOut != colOut.end(); itrOut++)
cout<<*itrOut<<" ";
cout<<endl;
return 0;
}
There is a catch though, the column part won't work for non-square 2D arrays (i.e for it to work row and column counts must be the same). I guess this can be worked around with a little more thought.
If your multidimensional vector is an actual multidimensional vector, for example something like std::vector<std::vector<int>>, which isn't suggested, then you will have to write your own iterator. It's not very complicated. Boost.Iterator has concepts that can be used to help implement it.
If your multidimensional vector is a single vector with it's size set to the product of the dimensions (i.e. width * height), which is the preferred way to handle this, then it's much easier. It can be done with the utilities provided by Boost.Range.
Here's a quick and dirty example of using Boost.Range. It could be made a little prettier with decltype. If your compiler doesn't support C++11 (specifically auto), I wouldn't suggest using this, because the code becomes very hard to read.
template<typename T>
boost::iterator_range<typename T::iterator>
GetRow(T& vec, typename T::size_type row, typename T::size_type w,
typename T::size_type h) {
return boost::make_iterator_range(
vec.begin() + (row * w),
vec.begin() + ((row + 1) * w)
);
}
template<typename T>
boost::strided_range<boost::iterator_range<typename T::iterator>>
GetColumn(T& vec, typename T::size_type col, typename T::size_type w,
typename T::size_type h) {
boost::iterator_range<typename T::iterator> range = boost::make_iterator_range(
vec.begin() + col,
vec.begin() + col + (h - 1) * w + 1
);
return boost::strided_range<boost::iterator_range<typename T::iterator>>(w, range);
}
And then using these functions is pretty easy, though again, it can become very ugly if your compiler doesn't support auto.
const size_t WIDTH = 3;
const size_t HEIGHT = 3;
std::vector<int> vec(WIDTH * HEIGHT);
// Fill the first row with 1.
auto row = GetRow(vec, 0, WIDTH, HEIGHT);
for (auto it = row.begin(); it != row.end(); ++it) {
(*it) = 1;
}
// Fill the second column with 2.
auto col = GetColumn(vec, 1, WIDTH, HEIGHT);
for (auto it = col.begin(); it != col.end(); ++it) {
(*it) = 2;
}
// Contents of vec is:
// 1 2 1
// 0 2 0
// 0 2 0
You may also want to look into Boost.MultiArray, which is a library intended for things like this. It provides the functionality you want, but it's definitely not the friendliest library.
For a 2D vector:
Rows will be straightforward:
const std::vector<int>& getRow( const std::vector<std::vector<int>>& input, int rowIdx )
{
return input.at( rowIdx );
}
Columns a little trickier:
std::vector<int> getColumn( const std::vector<std::vector<int>>& input, int colIdx )
{
std::vector<int> output;
for ( unsigned i = 0; i < input.size(); ++i )
output.push_back( input.at( i ).at( colIdx ) );
return output;
}
These functions basically take a 2D integer vector and return a row/column vector based on the specified index.
This is the basis for what you're trying to do (from what I can gather). Minor modification will allow you to apply a function to rows/columns selectively instead of merely returning them.