2-D array initialization

Ali Çehreli acehreli at yahoo.com
Sun Aug 2 19:13:11 UTC 2020


On 8/1/20 7:00 PM, Andy Balba wrote:

 >> >> ubyte[3][4] c = [ [5, 5, 5], [15, 15,15], [25, 25,25], [35,
 >> 35,35]  ];

 > Although not detailed in my original question, in my actual app
 > I have array ubyte [1000][3] Big which consists of research data I
 > obtained,
 >   and from which I want to randomly select 4 observations to construct
 > ubyte c[ ][ ].

It depends on how the data is layed out. Your original question makes me 
think the data is "code generated" into a D module and that's where you 
want to initialize that 2D fixed-length (static) array.

So, you simply want to import that module in your analysis program:

import data;

However, I really think the type should be ubyte[3][].

The following option reads the data from a file before analysis. 
Assuming the data is formatted one ubyte on a line:

--- 8< ---
5
5
5
15
15
15
25
25
25
35
35
35
--- 8< ---

then the following program does what you want:

import std.stdio : File, writefln;
import std.algorithm : map;
import std.range : array, chunks;
import std.string : strip;
import std.conv : to;
import std.random : choice;

auto parseData(string fileName) {
   return
     File(fileName)       // - Open the file
     .byLine              // - Iterate line-by-line as a range
                          //   (WARNING: same line buffer is
                          //   shared use byLineCopy if
                          //   necessary.)
     .map!strip           // - Strip the element
     .map!(to!ubyte)      // - Convert to ubyte
     .chunks(3)           // - Treat 3 consecutive elements as one
                          //   unit
     .map!(c => c.array)  // - Make an array from each chunk
     ;

   // NOTE: The returned range object is a chain of
   // operations to apply on fileName. Nothing will be read
   // from the file until the returned range is actually
   // used (i.e. the range is "lazy").
}

void main() {
   auto c = parseData("research_data")  // - The lazy range
            .array;                     // - As we want to pick
                                        //   random elements; we
                                        //   convert the data
                                        //   range to an
                                        //   array. This step is
                                        //   "eager": the entire
                                        //   file is parsed here.

   // Demonstrate that the type is a 2D array
   static assert (is (typeof(c) == ubyte[][]));

   // The rest is a random choice from that array:
   foreach (_; 0 .. 10) {
     auto chosen = c.choice;
     writefln!"chosen: %s"(chosen);
   }
}

If the three ubytes should actually be used as parts of a struct like 
Color, here is another approach:

import std.stdio;
import std.algorithm;
import std.range;
import std.string;
import std.conv;
import std.random;

struct Color {
   ubyte r;
   ubyte g;
   ubyte b;
}

// Assumes data is one ubyte per line
auto parseData(string fileName) {
   return
     File(fileName)
     .byLine
     .map!strip
     .map!(to!ubyte);
}

auto makeColors(R)(R range) {
   Color[] colors;

   while (!range.empty) {
     ubyte pop() {
       auto value = range.front;
       range.popFront();
       return value;
     }

     auto r = pop();
     auto g = pop();
     auto b = pop();

     colors ~= Color(r, g, b);
   }

   return colors;
}

void main() {
   auto data = parseData("research_data");

   auto c = makeColors(data);
   writefln!"data:\n%(%s\n%)"(c);

   foreach (_; 0 .. 10) {
     auto chosen = c.choice;
     writefln!"chosen: %s"(chosen);
   }
}

Sorry my liberal use of 'auto', which hides types. You can define 'c' 
with explicit types like Color[], or you can expose a variable's type at 
compile time with pragma(msg):

   pragma(msg, "the type: ", typeof(c));

That prints Color[] for the second program above.

Ali



More information about the Digitalmars-d-learn mailing list