www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to sort a 2D array by column

reply "katuday" <katuday teknobalangay.ph> writes:
I have a dynamic array of dynamic array of strings
I want to sort the outer array based on specific columns of the 
inner array

This is how I am populating the 2D array

void readFromFile()
{
	alias Row = string[];
	alias Table = Row[];
	
	Row the_row;
	Table the_table;
	
	auto inFile = File("sample.txt", "r");
	auto temp = chomp(inFile.readln()); // skip header
	while (!inFile.eof())
	{
		string row_in = chomp(inFile.readln());
		the_row = split(row_in,"\t");
		the_table ~= the_row;
	}
	writeln(the_table.length);
	the_table.sort; // I believe this sort uses all the columns 
inside the_row. What I want is use specific column(s)
}

This is my attemot to create a compare object. But I don't know 
how to use it together with .sort member function

class RowCompare
{
	int[] m_columns;
	
	this(int[] columns)
	{
		m_columns = m_columns;
	}
	
	int opCmp()(ref const Row lhs, ref const Row rhs) const
	{
		for (auto i = 0; i < m_columns.length; ++i)
		{
			ref const auto currentColumn = m_columns[i];
			if (lhs[currentColumn] < rhs[currentColumn] )
				return true;
			if (rhs[currentColumn] < lhs[currentColumn] )
				return false;
		}
	}
}
Jun 07 2014
next sibling parent reply "Chris Cain" <zshazz gmail.com> writes:
 This is my attemot to create a compare object. But I don't know 
 how to use it together with .sort member function
Don't use the .sort property. Use std.algorithm.sort, which has a "less" predicate (that should return a bool). http://dlang.org/phobos/std_algorithm.html#sort
Jun 07 2014
parent reply "Chris Cain" <zshazz gmail.com> writes:
On Saturday, 7 June 2014 at 19:14:01 UTC, Chris Cain wrote:
 This is my attemot to create a compare object. But I don't 
 know how to use it together with .sort member function
Don't use the .sort property. Use std.algorithm.sort, which has a "less" predicate (that should return a bool). http://dlang.org/phobos/std_algorithm.html#sort
Also note that the examples use a string to define the predicate, but it accepts functions as well. Such as: bool myCompareFunc(AType lhs, AType rhs) { return lhs.blah < rhs.blah; } //... AType[] arr; //... arr.sort!myCompareFunc();
Jun 07 2014
next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 06/07/2014 12:18 PM, Chris Cain wrote:

 Also note that the examples use a string to define the predicate, but it
 accepts functions as well. Such as:

      bool myCompareFunc(AType lhs, AType rhs)
      {
          return lhs.blah < rhs.blah;
      }

      //...
      AType[] arr;
      //...
      arr.sort!myCompareFunc();
Just for completeness, lambdas as well: arr.sort!((a, b) => a.blah < b.blah); Ali
Jun 07 2014
prev sibling parent reply "katuday" <katuday teknobalangay.ph> writes:
On Saturday, 7 June 2014 at 19:18:34 UTC, Chris Cain wrote:
 On Saturday, 7 June 2014 at 19:14:01 UTC, Chris Cain wrote:
 This is my attemot to create a compare object. But I don't 
 know how to use it together with .sort member function
Don't use the .sort property. Use std.algorithm.sort, which has a "less" predicate (that should return a bool). http://dlang.org/phobos/std_algorithm.html#sort
Also note that the examples use a string to define the predicate, but it accepts functions as well. Such as: bool myCompareFunc(AType lhs, AType rhs) { return lhs.blah < rhs.blah; } //... AType[] arr; //... arr.sort!myCompareFunc();
I need an example if you don't mind. My sort function requires columns numbers supplied at run-time This is how I defined my sort function bool compareRow(int[] columns, ref const Row lhs, ref const Row rhs) { bool ret = false; for (auto i = 0; i < columns.length; ++i) { const auto currentColumn = columns[i]; if (lhs[currentColumn] < rhs[currentColumn] ) ret = true; if (rhs[currentColumn] < lhs[currentColumn] ) ret = false; } return ret; } Calling sort like this does not compile sort!(compareRow)(sort_key,the_table);
Jun 07 2014
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 7 June 2014 at 20:47:31 UTC, katuday wrote:
 On Saturday, 7 June 2014 at 19:18:34 UTC, Chris Cain wrote:
 On Saturday, 7 June 2014 at 19:14:01 UTC, Chris Cain wrote:
 This is my attemot to create a compare object. But I don't 
 know how to use it together with .sort member function
Don't use the .sort property. Use std.algorithm.sort, which has a "less" predicate (that should return a bool). http://dlang.org/phobos/std_algorithm.html#sort
Also note that the examples use a string to define the predicate, but it accepts functions as well. Such as: bool myCompareFunc(AType lhs, AType rhs) { return lhs.blah < rhs.blah; } //... AType[] arr; //... arr.sort!myCompareFunc();
I need an example if you don't mind. My sort function requires columns numbers supplied at run-time This is how I defined my sort function bool compareRow(int[] columns, ref const Row lhs, ref const Row rhs) { bool ret = false; for (auto i = 0; i < columns.length; ++i) { const auto currentColumn = columns[i]; if (lhs[currentColumn] < rhs[currentColumn] ) ret = true; if (rhs[currentColumn] < lhs[currentColumn] ) ret = false; } return ret; }
That function don't make no sense (to me): It'll just return the result of the last iteration. It *looks* like you are trying to do a lexicographical comparison? You should just replace those "ret = XXX" with straight up "return XXX". The last "return ret" should be "return false" (I think)
 Calling sort like this does not compile

 sort!(compareRow)(sort_key,the_table);
You need to create a delegate that binds your sort key to have predicate that accepts exactly 2 arguments. A lambda will fill that role. sort!((lhs, rhs)=>compareRow(sort_key, a, b))(the_table); or (not tested) use std.functional's curry: sort!(curry!(compareRow, sort_key))(the_table);
Jun 07 2014
prev sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 7 June 2014 at 19:06:10 UTC, katuday wrote:
 	the_table.sort; // I believe this sort uses all the columns 
 inside the_row. What I want is use specific column(s)
Supposing you use the *function* "std.algorithm.sort", then that is going to sort you rows according to the (default) predicate "<". In this case, "<" means lexicographical comparison for arrays. EG: compares the first element, then the second, then the third, until 2 are different. I don't have your input, but here is an example program: import std.stdio, std.algorithm, std.random; //---- void main() { int[][] arr = new int[][](10, 10); foreach(i; 0 .. 10) foreach(j; 0 .. 10) { arr[i][j] = rndGen().front % 5; rndGen().popFront(); } writefln("%(%s\n%)", arr.sort()); //Note the "()": Very important. } //---- [0, 1, 0, 0, 0, 0, 2, 3, 1, 1] [0, 4, 4, 1, 2, 3, 4, 2, 1, 0] </-- [0, 4, 4, 1, 3, 4, 0, 2, 3, 3] </-- [2, 0, 0, 4, 1, 3, 3, 4, 2, 4] [2, 0, 4, 3, 3, 0, 2, 4, 2, 1] [3, 1, 2, 1, 1, 4, 1, 4, 1, 2] [3, 3, 2, 1, 0, 4, 0, 2, 3, 2] [4, 0, 0, 4, 3, 0, 4, 3, 4, 2] [4, 2, 1, 1, 1, 2, 0, 1, 2, 2] [4, 4, 3, 2, 2, 1, 1, 0, 4, 2] //---- As you can see here, this was ordered by looking up to 5 elements deep. If you need something more customize, you can do it by specifying your own function. For example, according to each row's Euclidean norm: //---- bool compare(int[] lhs, int[] rhs) { auto a = reduce!"a += b^2"(0, lhs); auto b = reduce!"a += b^2"(0, rhs); return a < b; } void main() { int[][] arr = new int[][](10, 4); foreach(i; 0 .. 10) foreach(j; 0 .. 4) { arr[i][j] = rndGen().front % 9 - 4; rndGen().popFront(); } writefln("%(%2s\n%)", arr.sort!compare); } //---- [-2, -3, -1, 3] [ 4, -2, -2, -2] [-2, 0, 2, -4] [ 3, -2, -4, 1] [ 3, -2, 2, 3] [-2, 3, 3, 0] [ 1, 2, 0, -2] [ 4, 2, -1, 0] [ 2, 1, 1, 3] [ 3, 3, 3, 4] //---- In the above examples, I used numbers, but the language really doesn't care, as long as your elements have strict total ordering according to the predicate you have used.
Jun 07 2014