1

I have the following codes, which sort a list of Info instances by multiple fields of the Info class. The lambda expression in Java8 makes things easy and clean. Therefore, I am wondering is there a similar way of doing so in C++? If not, what would be the closest (or most elegant way) to approach such multiple-field sorting? Thanks!

    public class Info {
        Info(int wi, int bi, int di) {
            w = wi;
            b = bi;
            d = di;
        }

        int w = -1;
        int b = -1;
        int d = -1;
    }

    List<Info> results = new ArrayList<Info>();

    Collections.sort(results, (a,b) -> { 
            if (a.d == b.d) {
                if(a.w == b.w) {
                    return a.b-b.b;
                } else {
                    return a.w - b.w;
                }
            } else {
                return a.d - b.d;
            }
    });
Vlad from Moscow
  • 224,104
  • 15
  • 141
  • 268
Edamame
  • 17,408
  • 44
  • 143
  • 254
  • 1
    Would suggest giving it a try and then coming back to post here. Anyway, even with the java code, you could do things better than the current implementation. That's a matter of code review but. – Naman Sep 03 '19 at 17:10
  • 1
    You could have googled "C++ lambda". – DeiDei Sep 03 '19 at 17:12
  • 1
    [This is the easy, clean Java way](https://stackoverflow.com/a/25501226/476716) – OrangeDog Sep 03 '19 at 17:36

1 Answers1

1

For example you can define the operator < for the class.

Here is a demonstrative program

#include <iostream>
#include <tuple>
#include <list>

class Info 
{
public: 
    Info( int wi, int bi, int di ) : w( wi ), b( bi ), d( di )
    {
    }

    friend bool operator <( const Info &, const Info & );

    friend std::ostream & operator << ( std::ostream &, const Info &info )
    {
        return std::cout << "{ " << info.d << ", " << info.w << ", " << info.b << " }"; 
    }

private:    
    int w = -1;
    int b = -1;
    int d = -1;
};

bool operator <( const Info &a, const Info &b )
{
    return std::tie( a.d, a.w, a.b ) < std::tie( b.d, b.w, b.b );
}

int main() 
{
    std::list<Info> lst = { { 1, 2, 3 },  { 1, 1, 2 }, { 1, 3, 2 }, { 2, 1, 2 }, { 2, 2, 3 } };

    lst.sort();

    for ( const auto &item : lst ) std::cout << item << '\n';

    return 0;
}

Its output is

{ 2, 1, 1 }
{ 2, 1, 3 }
{ 2, 2, 1 }
{ 3, 1, 2 }
{ 3, 2, 2 }

That is you can use the standard function std::tie that does the all work.

Or with the container std::vector

#include <iostream>
#include <tuple>
#include <vector>
#include <iterator>
#include <algorithm>

class Info 
{
public: 
    Info( int wi, int bi, int di ) : w( wi ), b( bi ), d( di )
    {
    }

    friend bool operator <( const Info &, const Info & );

    friend std::ostream & operator << ( std::ostream &, const Info &info )
    {
        return std::cout << "{ " << info.d << ", " << info.w << ", " << info.b << " }"; 
    }

private:    
    int w = -1;
    int b = -1;
    int d = -1;
};

bool operator <( const Info &a, const Info &b )
{
    return std::tie( a.d, a.w, a.b ) < std::tie( b.d, b.w, b.b );
}

int main() 
{
    std::vector<Info> v = { { 1, 2, 3 },  { 1, 1, 2 }, { 1, 3, 2 }, { 2, 1, 2 }, { 2, 2, 3 } };

    std::sort( std::begin( v ), std::end( v ) );

    for ( const auto &item : v ) std::cout << item << '\n';

    return 0;
}

You can use a lambda expression provided that you have access to the data members of the class for example through member functions.

#include <iostream>
#include <tuple>
#include <vector>
#include <iterator>
#include <algorithm>

class Info 
{
public: 
    Info( int wi, int bi, int di ) : w( wi ), b( bi ), d( di )
    {
    }

    int w = -1;
    int b = -1;
    int d = -1;
};

std::ostream & operator << ( std::ostream &, const Info &info )
{
    return std::cout << "{ " << info.d << ", " << info.w << ", " << info.b << " }"; 
}


int main() 
{
    std::vector<Info> v = { { 1, 2, 3 },  { 1, 1, 2 }, { 1, 3, 2 }, { 2, 1, 2 }, { 2, 2, 3 } };

    std::sort( std::begin( v ), std::end( v ), 
               []( const auto &a, const auto &b )
               {
                    return std::tie( a.d, a.w, a.b ) < std::tie( b.d, b.w, b.b );
               } );

    for ( const auto &item : v ) std::cout << item << '\n';

    return 0;
}
Vlad from Moscow
  • 224,104
  • 15
  • 141
  • 268