set with a special ordering

I have an array in a class with some numbers in a specific order. Now I want to create a set with references to that array ordered after the arrays content. I thought a solution could be something like
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Holder {
	int o[10]= {1,5,7,2,3,8,4,9,6,0};
public:
	set<int,my_order> m_s;
	Holder() {
		for(int i=0; i<10;i++) {
			m_s.insert(i);
		}
//here my_order should be something which result in the whished order
		set<int,my_order>::iterator it=m_s.begin();
		while(it!=m_s.end()) {
			cout<<*it<<" ";
			it++;
		}
		cout<<endl;
	}
};

int main() {
	Holder h;
	//wished output: 9,0,3,4,6,1,8,2,5,7
	return 0;
}

I just cant figure out how to create the my_order.
What shall I do?
I don't quite understand what order you want. o[0] = 1 what does that mean to the order? Can't see the connection between the array and your wished output, sorry could you clarify?
Use a custom comparison operation


!xy
<nolyc> You're trying to do X, and you thought of solution Y. So you're asking about solution Y, without even mentioning X. The problem is, there might be a better solution, but we can't know that unless
you describe what X is.
You can use either a comparison class or a comparison function, just like the example in the cpluplus.com reference entry for the std::set constructor.

set::set - Example
http://www.cplusplus.com/reference/set/set/set/#example

The class approach is preferred.

Andy
Last edited on
Ok. I try to clarify.
o[0]==1 and o[9]==0 means that the 9'th element is before the zero'th element. So in the new order I want 9 as the first element and 0 as the second.
I cannot use the class approach because a class will never have access to the array o
Create an indirect array with std::reference_wrapper<>
http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper

If the array contains arithmetic types, and arithmetic operations are to be performed in a different order, use std::valarray<> and std::indirect_array<>
http://www.cplusplus.com/reference/valarray/indirect_array/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <vector>
#include <functional>
#include <iomanip>
#include <valarray>

int main()
{
    {
        std::vector<int> seq { 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65 } ;
        for( int v : seq ) std::cout << v << ' ' ;
        std::cout << " (values)\n" ;

        for( std::size_t pos = 0 ; pos < seq.size() ; ++pos )
            std::cout << std::setw(2) << pos << ' ' ;
        std::cout << " (original order)\n" ; ;

        std::vector<std::size_t> order { 1, 9, 5, 7, 11, 2, 3, 8, 4, 6, 0, 10 } ;
        for( std::size_t pos : order ) std::cout << std::setw(2) << pos << ' ' ;
        std::cout << " (required order)\n" ; ;

        std::vector< std::reference_wrapper<int> > indirect ;
        for(std::size_t pos : order ) indirect.emplace_back( seq[pos] ) ;
        for( int v : indirect ) std::cout << v << ' ' ;
        std::cout << " (indirect)\n" ; ;
    }

    {
        std::valarray<int> seq { 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65 } ;
        std::valarray<std::size_t> order { 1, 9, 5, 7, 11, 2, 3, 8, 4, 6, 0, 10 } ;
        std::valarray<int> indirect { seq[order] } ;
        for( int v : indirect ) std::cout << v << ' ' ;
        std::cout << " (indirect)\n" ; ;
    }
}

http://ideone.com/tuLPZr
The last answer was interesting. But it did not use "set". The nice thing about set is that it does the odering for you. Here is an example which does what I want:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <set>

using namespace std;
int a[10]= {1,5,7,2,3,8,4,9,6,0};

struct OrderCompare {
    bool operator() (const int lhs, const int rhs) const {
      return a[lhs]<a[rhs];
    }
};


int main() {
	set<int,OrderCompare> s;
	for(int i=0; i<10; i++) {
		s.insert(i);
	}
	set<int,OrderCompare>::iterator it=s.begin();
	while(it!=s.end()) {
		cout<<*it<<" ";
		it++;
	}
	cout<<endl;
}

It produces:
$ ./test.exe
9 0 3 4 6 1 8 2 5 7

The only problem is that 'a' is a global variable and I want it to be a local variable of a class
You could pass the array to the constructor of the comparator.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <set>
#include <iostream>

using namespace std;

struct OrderCompare {
	OrderCompare(int* arr) : arr(arr) {}
    bool operator() (const int lhs, const int rhs) const {
      return arr[lhs]<arr[rhs];
    }
private:
    int* arr;
};


class Holder {
	int o[10]= {1,5,7,2,3,8,4,9,6,0};
public:
	set<int,OrderCompare> m_s;
	Holder() : m_s(OrderCompare(o)) {
		for(int i=0; i<10;i++) {
			m_s.insert(i);
		}
		set<int,OrderCompare>::iterator it=m_s.begin();
		while(it!=m_s.end()) {
			cout<<*it<<" ";
			it++;
		}
		cout<<endl;
	}
};

int main() {
	Holder h;
	return 0;
}

Last edited on
> The only problem is that 'a' is a global variable and I want it to be a local variable of a class

What's the problem? Store a reference to it in the predicate.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <iostream>
#include <set>
#include <vector>

struct A
{
    int member[10] {1,5,7,2,3,8,4,9,6,0};
    std::vector<std::size_t> another_member {5,6,7,8,9,0,1,2,3,4} ;
};

template < typename ORDER > struct order_compare
{
    order_compare( const ORDER& a ) : order(a) {}

    bool operator() (const int lhs, const int rhs) const
    { return order[lhs] < order[rhs] ; }

    const ORDER& order ;
};

int main()
{
    A object ;

    {
        std::set< int, order_compare< int[10] > > s( object.member ) ;
        for( int i=0 ; i<10 ; ++i ) s.insert(i);

        for( int v : s ) std::cout << v << ' ' ;
        std::cout << '\n' ;
    }

    {
        std::set< int, order_compare< std::vector<std::size_t> > > s( object.another_member ) ;
        for( int i=0 ; i<10 ; ++i ) s.insert(i);

        for( int v : s ) std::cout << v << ' ' ;
        std::cout << '\n' ;
    }
}

http://ideone.com/K4Dr0F
The last 2 answers were great thank you
Topic archived. No new replies allowed.