Thread overview
foreach(i,ref val; ndim_arr)??
May 09, 2016
Jay Norwood
May 10, 2016
ZombineDev
May 10, 2016
ag0aep6g
May 10, 2016
ZombineDev
May 10, 2016
ZombineDev
May 10, 2016
9il
May 10, 2016
9il
May 09, 2016
I noticed some discussion of Cartesian indexes in Julia, where the index is a tuple, along with some discussion of optimizing the index created for cache efficiency.  I could find foreach(ref val, m.byElement()), but didn't find an example that returned a tuple index.   Is that supported?

http://julialang.org/blog/2016/02/iteration

http://julialang.org/blog/2016/03/arrays-iteration


May 10, 2016
On Monday, 9 May 2016 at 18:50:32 UTC, Jay Norwood wrote:
> I noticed some discussion of Cartesian indexes in Julia, where the index is a tuple, along with some discussion of optimizing the index created for cache efficiency.  I could find foreach(ref val, m.byElement()), but didn't find an example that returned a tuple index.   Is that supported?
>
> http://julialang.org/blog/2016/02/iteration
>
> http://julialang.org/blog/2016/03/arrays-iteration

I guess you are talking about ndslice (http://dlang.org/phobos/std_experimental_ndslice).

There are various functions that can take static arrays, as well as tuples as parameters that are both cache-efficient. For example:

http://dlang.org/phobos-prerelease/std_experimental_ndslice_slice.html#.makeSlice and

http://dlang.org/phobos-prerelease/std_experimental_ndslice_slice.html#.Slice.opIndex

I also found the need for a byElement function that also provides the index. I guess it is a good idea for a pull request.
In the mean time, you can use the following:

auto indexed_range = lockstep(
    ndslice.byElement,
    ndslice.shape.indexSlice
);

foreach (ref elem; indexes; indexed_range)
    writefln("Element at %s = %s", indexes, elem);
May 10, 2016
Am 10.05.2016 um 12:21 schrieb ZombineDev:
> auto indexed_range = lockstep(

Tiny nitpick: lockstep doesn't return a range. It uses opApply to support foreach.
May 10, 2016
On Tuesday, 10 May 2016 at 13:52:27 UTC, ag0aep6g wrote:
> Am 10.05.2016 um 12:21 schrieb ZombineDev:
>> auto indexed_range = lockstep(
>
> Tiny nitpick: lockstep doesn't return a range. It uses opApply to support foreach.

Yes I know and I chose it in purpose, because it allows ref access to individual elements (zip returns a tuple which doesn't provide ref access). Otherwise my translation of OP wouldn't be accurate.
May 10, 2016
On Tuesday, 10 May 2016 at 10:21:30 UTC, ZombineDev wrote:
> On Monday, 9 May 2016 at 18:50:32 UTC, Jay Norwood wrote:
>> I noticed some discussion of Cartesian indexes in Julia, where the index is a tuple, along with some discussion of optimizing the index created for cache efficiency.  I could find foreach(ref val, m.byElement()), but didn't find an example that returned a tuple index.   Is that supported?
>>
>> http://julialang.org/blog/2016/02/iteration
>>
>> http://julialang.org/blog/2016/03/arrays-iteration
>
> I guess you are talking about ndslice (http://dlang.org/phobos/std_experimental_ndslice).
>
> There are various functions that can take static arrays, as well as tuples as parameters that are both cache-efficient. For example:
>
> http://dlang.org/phobos-prerelease/std_experimental_ndslice_slice.html#.makeSlice and
>
> http://dlang.org/phobos-prerelease/std_experimental_ndslice_slice.html#.Slice.opIndex
>
> I also found the need for a byElement function that also provides the index. I guess it is a good idea for a pull request.
> In the mean time, you can use the following:
>
> auto indexed_range = lockstep(
>     ndslice.byElement,
>     ndslice.shape.indexSlice
> );
>
> foreach (ref elem; indexes; indexed_range)
>     writefln("Element at %s = %s", indexes, elem);

Oops, this is not entirely correct. Sorry, I was on the phone and I couldn't verify it.

Here's a working example:

(You can try it at: https://dpaste.dzfl.pl/c0327f067fca)

import std.array : array;
import std.experimental.ndslice : byElement, indexSlice, sliced;
import std.range : iota, lockstep, zip;
import std.stdio : writefln;

void main()
{
    // needs .array for ref (lvalue) access
    // (iota offers only rvalues)
    auto slice = iota(2 * 3 * 4).array.sliced(2, 3, 4);

    auto indexed_range = lockstep(
        slice.shape.indexSlice.byElement(),
        slice.byElement()
    );

    writefln("%s", slice);

    foreach (idx, ref elem; indexed_range)
        writefln("Element at %s = %s", idx, ++elem);
}

[[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]]
Element at [0, 0, 0] = 1
Element at [0, 0, 1] = 2
Element at [0, 0, 2] = 3
Element at [0, 0, 3] = 4
Element at [0, 1, 0] = 5
Element at [0, 1, 1] = 6
Element at [0, 1, 2] = 7
Element at [0, 1, 3] = 8
Element at [0, 2, 0] = 9
Element at [0, 2, 1] = 10
Element at [0, 2, 2] = 11
Element at [0, 2, 3] = 12
Element at [1, 0, 0] = 13
Element at [1, 0, 1] = 14
Element at [1, 0, 2] = 15
Element at [1, 0, 3] = 16
Element at [1, 1, 0] = 17
Element at [1, 1, 1] = 18
Element at [1, 1, 2] = 19
Element at [1, 1, 3] = 20
Element at [1, 2, 0] = 21
Element at [1, 2, 1] = 22
Element at [1, 2, 2] = 23
Element at [1, 2, 3] = 24
May 10, 2016
On Monday, 9 May 2016 at 18:50:32 UTC, Jay Norwood wrote:
> I noticed some discussion of Cartesian indexes in Julia, where the index is a tuple, along with some discussion of optimizing the index created for cache efficiency.  I could find foreach(ref val, m.byElement()), but didn't find an example that returned a tuple index.   Is that supported?
>
> http://julialang.org/blog/2016/02/iteration
>
> http://julialang.org/blog/2016/03/arrays-iteration

This example is form documentation:
http://dlang.org/phobos/std_experimental_ndslice_selection.html#.byElement

import std.experimental.ndslice.slice;
auto slice = new long[20].sliced(5, 4);

for(auto elems = slice.byElement; !elems.empty; elems.popFront)
{
    size_t[2] index = elems.index;
    elems.front = index[0] * 10 + index[1] * 3;
}
assert(slice ==
    [[ 0,  3,  6,  9],
     [10, 13, 16, 19],
     [20, 23, 26, 29],
     [30, 33, 36, 39],
     [40, 43, 46, 49]]);

ndslice does not have opApply, because it overrides range primitives.
Iteration with byElement may be a little bit slower then iteration with common foreach loops. A method, say, `forElement` for `foreach` loops may be added, thought.

Best regards,
llya

May 10, 2016
On Tuesday, 10 May 2016 at 15:18:50 UTC, ZombineDev wrote:
> On Tuesday, 10 May 2016 at 10:21:30 UTC, ZombineDev wrote:
>
> (You can try it at: https://dpaste.dzfl.pl/c0327f067fca)
>
> import std.array : array;
> import std.experimental.ndslice : byElement, indexSlice, sliced;
> import std.range : iota, lockstep, zip;
> import std.stdio : writefln;
>
> void main()
> {
>     // needs .array for ref (lvalue) access
>     // (iota offers only rvalues)
>     auto slice = iota(2 * 3 * 4).array.sliced(2, 3, 4);
>
>     auto indexed_range = lockstep(
>         slice.shape.indexSlice.byElement(),
>         slice.byElement()
>     );
>
>     writefln("%s", slice);
>
>     foreach (idx, ref elem; indexed_range)
>         writefln("Element at %s = %s", idx, ++elem);
> }
>

The code above is slow because it calculates index using multiple assembler ops.

Following would be faster:

for(auto elems = slice.byElement; !elems.empty; elems.popFront)
{
    size_t[2] index = elems.index;
    elems.front = index[0] * 10 + index[1] * 3;
}

For really fast code just use multiple foreach loops:

foreach(i; matrix.length)
{
    auto row = matrix[i]; // optional
    foreach(j; matrix.length!1)
    {
        ...
    }
}