www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to define and use a custom comparison function

reply "belkin" <belkin yahoo.in.com> writes:
I am new to D so I am probably not using the right terminology 
but here is a piece of C++ code (not complete) that I would like 
to translate to idiomatic D.
I have defined a function object that I pass to std::sort to 
std:map as follows:

enum class SortOrder{ ASC, DESC };
typedef std::vector<boost::variant> DataRow; // this is one row 
of data in a 2D array. Data items are variants but this is not 
very important
typedef std::vector<DataRow> Data; // this is simply a 2D array
Data the_data;
// the function object is here. I don't want a lamda because I 
want to be able to call this from multiple places
class MyCompare
{
public:
	explicit MyCompare(int column, SortOrder order) : 
m_column(column), m_order(order) {}
	bool operator()(const DataRow& lhs, const DataRow& rhs)
	{
		switch (m_order)
		{
		case SortOrder::ASC:
			return lhs[m_column] < rhs[m_column];
		case SortOrder::DESC:
			return rhs[m_column] < lhs[m_column];
		}
	}
private:
	int m_column;
	SortOrder m_order;
};

example 1:
int column = 3;
SortOrder order = DESC;
std::sort(the_data.begin(), the_data.end(), MyCompare(column, 
order));

example 2:
MyCompare comp(column, order);
std::map<DataRow, Data, MyCompare> mp( comp );

What is the equivalent idiomatic D?
Jun 15 2014
parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
You can pass anything to the sort function that's callable, 
including an object:

     struct MyCompare {
         SortOrder order;
         int column;
         bool opCall(const ref DataRow lhs, const ref DataRow rhs) 
{
             return order == SortOrder.ASC ?
                 lhs[column] < rhs[column] :
                 rhs[column] < lhs[column];
         }
     }

     import std.algorithm;
     MyCompare cmp(SortOrder.ASC, 10);
     my_columns.sort!cmp;

(Untested.)
Jun 16 2014
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 16 June 2014 at 09:24:22 UTC, Marc Schütz wrote:
 You can pass anything to the sort function that's callable, 
 including an object:

     struct MyCompare {
         SortOrder order;
         int column;
         bool opCall(const ref DataRow lhs, const ref DataRow 
 rhs) {
             return order == SortOrder.ASC ?
                 lhs[column] < rhs[column] :
                 rhs[column] < lhs[column];
         }
     }

     import std.algorithm;
     MyCompare cmp(SortOrder.ASC, 10);
     my_columns.sort!cmp;

 (Untested.)
That works, but it's not very idiomatic. Well, I have never seen a C++ style "functor" used in D template is what I'm saying. I don't know if that's good or bad. A more idiomatic approach would be to simply pass a delegate to your function. This can either be as a pointer to member function: struct MyCompare { SortOrder order; int column; bool compare(const ref DataRow lhs, const ref DataRow rhs) { return order == SortOrder.ASC ? lhs[column] < rhs[column] : rhs[column] < lhs[column]; } } import std.algorithm; MyCompare cmp(SortOrder.ASC, 10); auto dg = &cmp.compare; my_columns.sort!dg; Or, more generally, via a lambda, or a function with state: import std.algorithm; column = 10; bool compare(const ref DataRow lhs, const ref DataRow rhs) { return order == SortOrder.ASC ? lhs[column] < rhs[column] : rhs[column] < lhs[column]; } } my_columns.sort!compare;
Jun 16 2014
parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Monday, 16 June 2014 at 20:49:29 UTC, monarch_dodra wrote:
 MyCompare cmp(SortOrder.ASC, 10);
This syntax is not valid D. It should be: auto cmp = MyCompare(SortOrder,ASC, 10);
Jun 16 2014
next sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Tuesday, 17 June 2014 at 04:32:20 UTC, Jakob Ovrum wrote:
 On Monday, 16 June 2014 at 20:49:29 UTC, monarch_dodra wrote:
 MyCompare cmp(SortOrder.ASC, 10);
This syntax is not valid D. It should be: auto cmp = MyCompare(SortOrder,ASC, 10);
Sorry, that first comma is a typo and should be a dot. auto cmp = MyCompare(SortOrder.ASC, 10);
Jun 16 2014
prev sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 17 June 2014 at 04:32:20 UTC, Jakob Ovrum wrote:
 On Monday, 16 June 2014 at 20:49:29 UTC, monarch_dodra wrote:
 MyCompare cmp(SortOrder.ASC, 10);
This syntax is not valid D. It should be: auto cmp = MyCompare(SortOrder,ASC, 10);
Well, techincally, the *syntax* is valid. If "MyCompare" contains a constructor, it's legit code to boot. It's part of the uniform initialization syntax, and it's what allows things like: BigInt b = 5; or BigInt b(5); THAT said, yeah, the MyCompare I posted did not contain a constructor. SO my code was wrong, guilty as charged.
Jun 17 2014
parent "TheFlyingFiddle" <kurtyan student.chalmers.se> writes:
On Tuesday, 17 June 2014 at 07:53:51 UTC, monarch_dodra wrote:
 On Tuesday, 17 June 2014 at 04:32:20 UTC, Jakob Ovrum wrote:
 On Monday, 16 June 2014 at 20:49:29 UTC, monarch_dodra wrote:
 MyCompare cmp(SortOrder.ASC, 10);
This syntax is not valid D. It should be: auto cmp = MyCompare(SortOrder,ASC, 10);
Well, techincally, the *syntax* is valid. If "MyCompare" contains a constructor, it's legit code to boot. It's part of the uniform initialization syntax, and it's what allows things like: BigInt b = 5; or BigInt b(5); THAT said, yeah, the MyCompare I posted did not contain a constructor. SO my code was wrong, guilty as charged.
Since when is that syntax valid? Is there somewhere it is documented?
Jun 17 2014