Thread overview
Rotate array in writefln?
Apr 18, 2018
Chris Katko
Apr 18, 2018
Stefan Koch
Apr 18, 2018
Simen Kjærås
Apr 19, 2018
Chris Katko
Apr 19, 2018
Simen Kjærås
April 18, 2018
I need to rotate an array by 90 degrees, or have writefln figure that out.

I need, say:

0 4 5 6
0 0 0 0
0 0 0 0
0 0 0 0

But it's outputting:

0 0 0 0
4 0 0 0
5 0 0 0
6 0 0 0

int [4][4] data;
file.writeln(format("%(%-(%d %)\n%)", data));


April 18, 2018
On Wednesday, 18 April 2018 at 06:54:29 UTC, Chris Katko wrote:
> I need to rotate an array by 90 degrees, or have writefln figure that out.
>
> I need, say:
>
> 0 4 5 6
> 0 0 0 0
> 0 0 0 0
> 0 0 0 0
>
> But it's outputting:
>
> 0 0 0 0
> 4 0 0 0
> 5 0 0 0
> 6 0 0 0
>
> int [4][4] data;
> file.writeln(format("%(%-(%d %)\n%)", data));

You can transpose the matrix :)
April 18, 2018
On Wednesday, 18 April 2018 at 06:54:29 UTC, Chris Katko wrote:
> I need to rotate an array by 90 degrees, or have writefln figure that out.
>
> I need, say:
>
> 0 4 5 6
> 0 0 0 0
> 0 0 0 0
> 0 0 0 0
>
> But it's outputting:
>
> 0 0 0 0
> 4 0 0 0
> 5 0 0 0
> 6 0 0 0
>
> int [4][4] data;
> file.writeln(format("%(%-(%d %)\n%)", data));

Generally, the solution would be std.range.transposed. However, since you're using a int[4][4], that's not a range-of-ranges, and transposed don't work out of the box. This helper function should help:

T[][] ror(T, size_t N1, size_t N2)(ref T[N1][N2] arr)
{
    T[][] result = new T[][N2];
    foreach (i, e; arr) {
        result[i] = e.dup;
    }
    return result;
}

unittest
{
    import std.stdio;
    import std.range;

    int [4][4] data;
    data[2][3] = 4;
    writefln("%(%-(%d %)\n%)", data);
    writefln("%(%-(%d %)\n%)", data.ror.transposed);
}

--
  Simen
April 19, 2018
On Wednesday, 18 April 2018 at 07:15:47 UTC, Simen Kjærås wrote:
> On Wednesday, 18 April 2018 at 06:54:29 UTC, Chris Katko wrote:
>> I need to rotate an array by 90 degrees, or have writefln figure that out.
>>
>> I need, say:
>>
>> 0 4 5 6
>> 0 0 0 0
>> 0 0 0 0
>> 0 0 0 0
>>
>> But it's outputting:
>>
>> 0 0 0 0
>> 4 0 0 0
>> 5 0 0 0
>> 6 0 0 0
>>
>> int [4][4] data;
>> file.writeln(format("%(%-(%d %)\n%)", data));
>
> Generally, the solution would be std.range.transposed. However, since you're using a int[4][4], that's not a range-of-ranges, and transposed don't work out of the box. This helper function should help:
>
> T[][] ror(T, size_t N1, size_t N2)(ref T[N1][N2] arr)
> {
>     T[][] result = new T[][N2];
>     foreach (i, e; arr) {
>         result[i] = e.dup;
>     }
>     return result;
> }
>
> unittest
> {
>     import std.stdio;
>     import std.range;
>
>     int [4][4] data;
>     data[2][3] = 4;
>     writefln("%(%-(%d %)\n%)", data);
>     writefln("%(%-(%d %)\n%)", data.ror.transposed);
> }
>
> --
>   Simen

That makes sense why transpose wouldn't work for my arrays!

So you're saying if I used [][] (dynamic array) that's a range of ranges, and it would work?

Why is it you have to rework your templates for static vs dynamic ranges? Thanks!
April 19, 2018
On Thursday, 19 April 2018 at 10:10:41 UTC, Chris Katko wrote:
> That makes sense why transpose wouldn't work for my arrays!
>
> So you're saying if I used [][] (dynamic array) that's a range of ranges, and it would work?

Yup. Static arrays can't be ranges, since popFront must mutate the length, and the length is a part of the type for static arrays.


> Why is it you have to rework your templates for static vs dynamic ranges? Thanks!

Unless I answered this question above, I'm not entirely sure what you're asking.

Anyways, for matrix work (which seems to be what you're doing), I would suggest taking a look at https://github.com/libmir/mir-algorithm. I haven't actually used it myself, but seems to be a very good and comprehensive library for this purpose.

--
  Simen
April 19, 2018
On 4/18/18 3:15 AM, Simen Kjærås wrote:
> On Wednesday, 18 April 2018 at 06:54:29 UTC, Chris Katko wrote:
>> I need to rotate an array by 90 degrees, or have writefln figure that out.
>>
>> I need, say:
>>
>> 0 4 5 6
>> 0 0 0 0
>> 0 0 0 0
>> 0 0 0 0
>>
>> But it's outputting:
>>
>> 0 0 0 0
>> 4 0 0 0
>> 5 0 0 0
>> 6 0 0 0
>>
>> int [4][4] data;
>> file.writeln(format("%(%-(%d %)\n%)", data));
> 
> Generally, the solution would be std.range.transposed. However, since you're using a int[4][4], that's not a range-of-ranges, and transposed don't work out of the box. This helper function should help:
> 
> T[][] ror(T, size_t N1, size_t N2)(ref T[N1][N2] arr)
> {
>      T[][] result = new T[][N2];
>      foreach (i, e; arr) {
>          result[i] = e.dup;
>      }
>      return result;
> }
> 
> unittest
> {
>      import std.stdio;
>      import std.range;
> 
>      int [4][4] data;
>      data[2][3] = 4;
>      writefln("%(%-(%d %)\n%)", data);
>      writefln("%(%-(%d %)\n%)", data.ror.transposed);
> }


A version without allocating:

T[][N2] ror(T, size_t N1, size_t N2)(ref T[N1][N2] arr)
{
    T[][N2] result;
    foreach (i, ref e; arr) {
        result[i] = e[];
    }
    return result;
}

...

writefln("%(%-(%d %)\n%)" data.ror[].transposed); // need the slice operator here

Keep in mind, you can't simply assign a variable to data.ror[], as the backing goes away immediately (OK to use as an rvalue though). And you must keep data in scope as long as you are using the result of data.ror.

-Steve