Thread overview
Initializing an associative array of struct
Jun 14, 2020
Denis
Jun 14, 2020
Kagamin
Jun 14, 2020
Kagamin
Jun 14, 2020
Stanislav Blinov
Jun 14, 2020
Denis
Jun 14, 2020
Ali Çehreli
Jun 14, 2020
Denis
June 14, 2020
Hi,

I'm trying to combine a couple of general types (associative array, struct) in a compound data structure, but without success. Here is what I'm trying to achieve:

    "param" is a string variable
    "parameters[param].id" is an integer value
    "parameters[param].value" is a string value

param can be any of a fixed set of string values, all literals known at compile time.

parameters needs to be pre-populated with all of its keys during initialization, because they will be used to validate the param values that are read from a file (by checking if "param in parameters" is true).

I started with the following declarations:

    struct Parameter {
        int id;
        string value; }

    Parameter[string] parameters;
    string param;

But then I simply could not come up with a way to initialize the keys of parameters. I tried using assignments as well as enum, but always received either a compile or a runtime error. (Unfortunately the error messages did not enable me to find a solution.)

Note also that the defaults for id and value are fine (int and string defaults). But is it even possible to add the keys alone to parameters, without assigning something?

I would welcome a suggestion for how to initialize the keys of parameters. As there will be a couple dozen of the param string keys, a more succinct method would be preferable over a verbose one.

I realize that this is a very basic question, but I'm stumped!

Thank you in advance for your help.
June 14, 2020
string param="aa";
parameters[param]=Parameter();
in id=parameters[param].id;
June 14, 2020
that's
int id=parameters[param].id;
June 14, 2020
On Sunday, 14 June 2020 at 04:36:09 UTC, Denis wrote:

> Note also that the defaults for id and value are fine...

> I would welcome a suggestion for how to initialize the keys of parameters. As there will be a couple dozen of the param string keys, a more succinct method would be preferable over a verbose one.

Param[string] parameters;
string[] keys =
[
"huh", "buh", "hrm", "pff", "err", "ack", "ugh",
/* ... */
"zzz"
];
foreach (k; keys)
    parameters.require(k);

https://dlang.org/spec/hash-map.html#inserting_if_not_present

The `require` function, when called only with key, will insert default (.init) value for that key.
June 14, 2020
@Kagamin:

On Sunday, 14 June 2020 at 07:16:18 UTC, Kagamin wrote:
> parameters[param]=Parameter();

I did not realize that you can use a type on the RHS of an assignment, but it is clear and succinct. This syntax will be very useful going forward -- thank you.

@Stanislav B:

On Sunday, 14 June 2020 at 09:34:08 UTC, Stanislav Blinov wrote:
> string[] keys =
> [
> "huh", "buh", "hrm", "pff", "err", "ack", "ugh",
> /* ... */
> "zzz"
> ];
> foreach (k; keys)
>     parameters.require(k);

This solves the problem of initializing the keys perfectly -- thank you. There does not appear to be a way to loop over the elements of an enum, so a string array does make the most sense as the initial container for the keys.

I should add that your explanation for using `require` to perform the init is much more clear than the documentation!

> The `require` function, when called only with key, will insert default (.init) value for that key.

I am just starting to learn D, and am missing so many pieces of the puzzle that I'm not yet able to always put "two and two" together myself. This kind of help really goes a long way. Again, my thanks to you both.

Denis
June 14, 2020
On 6/14/20 7:43 AM, Denis wrote:> @Kagamin:
>
> On Sunday, 14 June 2020 at 07:16:18 UTC, Kagamin wrote:
>> parameters[param]=Parameter();
>
> I did not realize that you can use a type on the RHS of an assignment,

Note that it's not just the type but with parenthesis after it. For example, Foo() default-constructs an object of Foo.

> There does not appear to be a way to loop over the elements of an enum,

There is std.traits.EnumMembers:

import std.traits;

enum Foo { abc, xyz }

void main() {
  foreach (foo; EnumMembers!Foo) {
    // ...
  }
}

Ali

June 14, 2020
On Sunday, 14 June 2020 at 15:44:04 UTC, Ali Çehreli wrote:
> On 6/14/20 7:43 AM, Denis wrote:> @Kagamin:
> >
> > On Sunday, 14 June 2020 at 07:16:18 UTC, Kagamin wrote:
> >> parameters[param]=Parameter();
> >
> > I did not realize that you can use a type on the RHS of an
> assignment,
>
> Note that it's not just the type but with parenthesis after it. For example, Foo() default-constructs an object of Foo.

Got it.

> > There does not appear to be a way to loop over the elements
> of an enum,
>
> There is std.traits.EnumMembers:
>
> import std.traits;
>
> enum Foo { abc, xyz }
>
> void main() {
>   foreach (foo; EnumMembers!Foo) {
>     // ...
>   }
> }

Excellent. Because all of the keys are immutable strings and are known at compile time, enum seems like it should be well suited for the job. I will try this too.

On a side note: I am working my way through your book, Ali. It really is very helpful for learning D, and for pointing out things that are not always clear from reading the documentation alone. I will admit, however, that I am not able to absorb all of the more subtle aspects yet. So this is an iterative process (read some, write code, re-read and read some more, write code, ...)

Thank you for your help.