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