www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Multidimensional arrays, foreach loops and slices

reply "Joseph Rushton Wakeling" <joseph.wakeling webdrake.net> writes:
Hello all,

A couple of queries.  The first I'm sure has been asked/answered 
definitively before, but a search doesn't bring anything up: is 
it possible to foreach() over every element of a multidimensional 
array, i.e. something like,

     int[3][4][5] a;

     foreach(ref int n; a)
         n = uniform!"[]"(0, 1);

... or is it necessary to do a separate foreach over each 
dimension?

The second query relates to slices.  Suppose I have an N*M 2d 
array (let's call it a), and a 1d array of length N (let's call 
it s) whose elements are unsigned integers whose values fall in 
[0, M).  What I'd like is to take a slice of a such that I get 
out a 1d array of length N such that the i'th element corresponds 
to a[s[i]].

Is this possible?  And if so, how is it achieved?

Thanks and best wishes,

     -- Joe
May 30 2012
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Joseph Rushton Wakeling:

 A couple of queries.

I think you have to write two small generic functions to do those things (or write inline code). Bye, bearophile
May 30 2012
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Wed, May 30, 2012 at 6:15 PM, Joseph Rushton Wakeling
<joseph.wakeling webdrake.net> wrote:
 Hello all,

 A couple of queries. =C2=A0The first I'm sure has been asked/answered
 definitively before, but a search doesn't bring anything up: is it possib=

 to foreach() over every element of a multidimensional array, i.e. somethi=

 like,

 =C2=A0 =C2=A0int[3][4][5] a;

 =C2=A0 =C2=A0foreach(ref int n; a)
 =C2=A0 =C2=A0 =C2=A0 =C2=A0n =3D uniform!"[]"(0, 1);

 ... or is it necessary to do a separate foreach over each dimension?

When you use foreach on a, it will iterate on a's elements, in this case the bidimensional subarrays. You'll have to foreach separately on each dimension to act on individual, scalar, elements. Of course, D can automate this for you: module test; import std.algorithm; import std.random; import std.range; import std.stdio; template rank(R) { static if (isInputRange!R) enum size_t rank =3D 1 + rank!(ElementType!R); else enum size_t rank =3D 0; } /** Maps fun at depth downToRank inside a range of ranges. */ auto depthMap(alias fun, int downToRank =3D 0, R)(R range) { static if (0<=3D downToRank && downToRank < rank!R) return map!(depthMap!(fun, downToRank, ElementType!R))(range); else // rank!R =3D=3D 0 -> range is a scalar, not a range return fun(range); } int fill(int _) { return uniform!"[]"(0,1);} void main() { auto r =3D [[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0],[0,0,0],[0,0,0]],[[0,0,0= ],[0,0,0],[0,0,0]]]; auto d =3D depthMap!fill(r); writeln(r); writeln(d); }
 The second query relates to slices. =C2=A0Suppose I have an N*M 2d array =

 call it a), and a 1d array of length N (let's call it s) whose elements a=

 unsigned integers whose values fall in [0, M). =C2=A0What I'd like is to =

 slice of a such that I get out a 1d array of length N such that the i'th
 element corresponds to a[s[i]].

 Is this possible? =C2=A0And if so, how is it achieved?

You meant a[i][s[i]], right? auto a =3D [[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]]; auto s =3D [4,3,2]; auto slice =3D map!( i =3D> a[i][s[i]])(iota(0,3)); writeln(slice); This is a lazy range whose elements are a[i][s[i]]. If you're not afraid of allocating everything at once, call std.range.array() on it to transform it into an array: auto slice2 =3D array(slice); writeln(typeof(slice2).stringof); Philippe
May 30 2012