Thread overview
How to sort a 2D array by column
Jun 07, 2014
katuday
Jun 07, 2014
Chris Cain
Jun 07, 2014
Chris Cain
Jun 07, 2014
Ali Çehreli
Jun 07, 2014
katuday
Jun 07, 2014
monarch_dodra
Jun 07, 2014
monarch_dodra
June 07, 2014
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;
		}
	}
}
June 07, 2014
> 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
June 07, 2014
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();
June 07, 2014
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

June 07, 2014
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.
June 07, 2014
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);

June 07, 2014
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);