A better way to sort this char pair?

Mar 30, 2019 at 3:51pm
Hello once again :)

So currently I'm trying to sort a pair that takes a int and a char.
And after it takes those values it runs a "strange type of bubblesort" to make sure the char 'R' comes before the char 'G' and the char 'G' comes before 'B' essentialy RGB. It works as intended if i input the values :

1
2
3
4
5
6
5
1 B
3 R
4 B
6 G
9 R


It comes out as i want it to be :
1
2
3
4
5
3 R
9 R	
6 G
1 B
4 B


Although this is valid, i feel like my solution is very very complicated and it can be done a better way, but i'm not sure what exactly that would be and in some cases its a bit slow.
Also if you try to insert for example '2 B' it would not sort the number as :
1
2
3
1 B
2 B
4 B


But instead you will get
1
2
3
1 B
4 B
2 B


I kind of found a way to also fix that with the current sorting, but it seems very complicated and unlogical.
So i really hope you guys can advice me a better way to make this work better as it is kind of obvious it might be a bad method.

Thank once again, if there is something i explained poorly i'm looking forward to explain it in more details.

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#include <string>
#define MAXN 1000000
using namespace std;

pair<int, char> rgb[MAXN];
int n;
void charSort()
{
    int i, j;
    char ourChar;
    int h;
    for(i=n-2; i>=0; i--){
    for(j=0; j<=i; j++)
    {
        if(rgb[j].second !='R' && rgb[j+1].second == 'R')
        {
            ourChar=rgb[j].second; rgb[j].second= rgb[j+1].second;
            h = rgb[j].first; rgb[j].first=rgb[j+1].first;
            rgb[j+1].second= ourChar;
            rgb[j+1].first=h;
        }
        else if(rgb[j].second !='G' && rgb[j+1].second == 'G' && rgb[j].second !='R')
        {
            ourChar=rgb[j].second; rgb[j].second= rgb[j+1].second;
            h = rgb[j].first; rgb[j].first=rgb[j+1].first;
            rgb[j+1].second= ourChar;
            rgb[j+1].first=h;
        }
    }
 }
}

int main() {

    int i,j;
    scanf("%d", &n);
    for(i = 0 ; i < n; i++)
    {
        int a;
        char b;
        cin >> a >> b;
        rgb[i] = make_pair(a, b);
    }

    charSort();
    for(i = 0; i < n; i++)
    {
       cout << rgb[i].first << " " << rgb[i].second << "\n";

    }

    return 0;
}
Mar 30, 2019 at 4:10pm
You want to sort first by the char, descending, and then by the int, ascending?

The pair's default ordering is first by int, ascending, and then by char, ascending.
http://www.cplusplus.com/reference/utility/pair/operators/
1
2
3
4
5
template <class T1, class T2>
  bool operator<  (const pair<T1,T2>& lhs, const pair<T1,T2>& rhs)
{
  return lhs.first<rhs.first || (!(rhs.first<lhs.first) && lhs.second<rhs.second);
}


You'll need something like:
1
2
3
4
5
template <class T1, class T2>
  bool myorder(const pair<T1,T2>& lhs, const pair<T1,T2>& rhs)
{
  return lhs.second>rhs.second || (!(rhs.second>lhs.second) && lhs.first<rhs.first);
}

Then std::sort could do the ordering: std::sort( std::begin(rgb), std::end(rgb), myorder );
Mar 30, 2019 at 4:19pm
@keskiverto

I tried something similar, but in such case it would not accept the third argument in this example "myorder" to sort it by that.

 
rgb2.cpp|35|note:   candidate expects 2 arguments, 3 provided|
Last edited on Mar 30, 2019 at 4:20pm
Mar 30, 2019 at 4:31pm
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 <utility>
#include <algorithm>
#include <iterator>

enum colour_t { RED = 1, GREEN = 2, BLUE = 4 };

inline std::pair< colour_t, int > translate( std::pair< int, char > icpair )
{
    if( icpair.second == 'G' || icpair.second == 'g' ) return { GREEN, icpair.first } ;
    else if( icpair.second == 'B' || icpair.second == 'b' ) return { BLUE, icpair.first } ;
    else return { RED, icpair.first } ;
}

int main()
{
    std::pair< int, char > rgb[] { {5,'B'}, {8,'R'}, {1,'G'}, {2,'B'}, {2,'G'}, {7,'R'},
                                   {5,'R'}, {8,'B'}, {8,'G'}, {6,'B'}, {7,'G'}, {9,'R'} } ;


    std::sort( std::begin(rgb), std::end(rgb),
               []( const auto& icpa, const auto& icpb ) { return translate(icpa) < translate(icpb) ; } ) ;

    for( const auto& icp : rgb ) std::cout << icp.first << ' ' << icp.second << '\n' ;
}

http://coliru.stacked-crooked.com/a/052d4d67a1b5cc7d
Mar 30, 2019 at 4:38pm
Thanks for both your imputs guys.

I actually managed to make @keskiverto example also work perfectly.
I should read more the documentation next time ! :)

Thank you also @JLBorges also very nice interesting solution.
Topic archived. No new replies allowed.