www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to sort a multidimensional ndslice?

reply Arredondo <arm.plus gmail.com> writes:
I want to sort a two-dimensional ndslice by its columns according 
to some predefined predicate.

What I mean is _not_ sorting the contents of each column 
individually, but instead to reorder the entire columns of the 
matrix so that they are sorted according to some "greater than" 
function.

Here's a MWE (the `larger` function is just an example):

```
import std.stdio;

import mir.ndslice.slice;
import mir.ndslice.sorting;

void main() {
     auto a = [[1, -1, 3, 2],
               [0, -2, 3, 1]].sliced;

     writeln(a);
     a.byDim!1.sort!((u, v) => larger(u, v));
     writeln(a);
}

auto larger(C)(C u, C v) {
     import mir.math.sum : sum;
     return sum(u) > sum(v);
}
```

I would have expected this to print:
[[1, -1, 3, 2], [0, -2, 3, 1]]
[[3, 2, 1, -1], [3, 1, 0, -2]]

but instead it prints
[[1, -1, 3, 2], [0, -2, 3, 1]]
[[1, -1, 3, 2], [0, -2, 3, 1]]

i.e, nothing happens!
Any suggestions?

Arredondo.
Aug 17 2020
parent reply 9il <ilyayaroshenko gmail.com> writes:
The following code just sorts each row:

------
/+dub.sdl:
dependency "mir-algorithm" version="~>3.9.24"
+/
import mir.ndslice;
import mir.ndslice.sorting;
import mir.algorithm.iteration: each;

void main() {
	// fuse, not sliced if you use an array of arrays for argument
     auto a = [[1, -1, 3, 2],
               [0, -2, 3, 1]].fuse;

     // make an index
	a.byDim!0.each!(sort!larger);

	import std.stdio;
     writeln(a);
   // [[3, 2, 1, -1], [3, 1, 0, -2]]
}

auto larger(C)(C u, C v) {
     return u > v;
}
------



To reorder the columns data according to precomputed index:

------
/+dub.sdl:
dependency "mir-algorithm" version="~>3.9.24"
+/
import mir.ndslice;
import mir.series;
import mir.ndslice.sorting;
import mir.algorithm.iteration: each;
import mir.math.sum;

void main() {
	// fuse, not sliced if you use an array of arrays for argument
     auto a = [[1, -1, 3, 2],
               [0, -2, 3, 1]].fuse;

     // make an index
	auto index = a.byDim!1.map!sum.slice;

     auto s = index.series(a.transposed);
     auto indexBuffer = uninitSlice!int(s.length);
     auto dataBuffer = uninitSlice!int(s.length);
     sort!larger(s, indexBuffer, dataBuffer);

     import std.stdio;
     writeln(a);
    /// [[3, 2, 1, -1], [3, 1, 0, -2]]
}

auto larger(C)(C u, C v) {
     return u > v;
}

-----
Aug 17 2020
parent reply Arredondo <arm.plus gmail.com> writes:
On Tuesday, 18 August 2020 at 04:07:56 UTC, 9il wrote:
 To reorder the columns data according to precomputed index:
 auto index = a.byDim!1.map!sum.slice;
Hello Ilya, thanks for the answer! Unfortunately I can't use it because I don't have (and can't define) a sorting index for my columns. I only have a predicate `larger(c1, c2)` that compares two columns to decide which one is "larger". Cheers! Armando.
Aug 18 2020
next sibling parent James Blachly <james.blachly gmail.com> writes:
On Tuesday, 18 August 2020 at 13:07:56 UTC, Arredondo wrote:
 On Tuesday, 18 August 2020 at 04:07:56 UTC, 9il wrote:
 To reorder the columns data according to precomputed index:
 auto index = a.byDim!1.map!sum.slice;
Hello Ilya, thanks for the answer! Unfortunately I can't use it because I don't have (and can't define) a sorting index for my columns. I only have a predicate `larger(c1, c2)` that compares two columns to decide which one is "larger". Cheers! Armando.
Armando, I believe you can just pass your predicate to the sort! template http://docs.algorithm.dlang.io/latest/mir_ndslice_sorting.html
Aug 18 2020
prev sibling parent 9il <ilyayaroshenko gmail.com> writes:
On Tuesday, 18 August 2020 at 13:07:56 UTC, Arredondo wrote:
 On Tuesday, 18 August 2020 at 04:07:56 UTC, 9il wrote:
 To reorder the columns data according to precomputed index:
 auto index = a.byDim!1.map!sum.slice;
Hello Ilya, thanks for the answer! Unfortunately I can't use it because I don't have (and can't define) a sorting index for my columns. I only have a predicate `larger(c1, c2)` that compares two columns to decide which one is "larger". Cheers! Armando.
This should work. But reallocates the data. /+dub.sdl: dependency "mir-algorithm" version="~>3.9.24" +/ import std.stdio; import mir.array.allocation; import mir.ndslice; import mir.ndslice.sorting; void main() { auto a = [[1, -1, 3, 2], [0, -2, 3, 1]].fuse; writeln(a); auto b = a.byDim!1.array; b.sort!larger; auto c = b.fuse!1; writeln(c); } auto larger(C)(C u, C v) { import mir.math.sum : sum; return sum(u) > sum(v); }
Aug 19 2020