www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Multidimensional AA question

reply =?UTF-8?B?QW5kcsOp?= <Andre nospam.org> writes:
Hi,

I have a maybe trivial question on how to insert or update a 
given entry in a multidimensional AA. So I have this AA:

    /// language, chapter, section. Content is a magic struct
    Content[int][string][string] contentAA;

In some part of my code I want to either add a complete new entry 
or update an existing one. I just came up with this solution but 
it seems complex to me:

    string language, chapter;
    int section;
    Content* content;
    if (auto l = language in contentAA) {
        if (auto c = chapter in *l) {
               content = section in *c;
        }
    }
    if (!content) {
        contentAA[language][chapter][section] = Content();
        content = &contentAA[language][chapter][section];
    }
    /// work with content regardless whether it is updated or 
newly inserted

My question now is: is there some more elegant solution to 
achieve this? Something like in C++ when you have std::map's of 
std::map's and just access the elements and the entry is created 
implicitly? Basically I would want to just have this line working 
out of the box:

    content = &contentAA[language][chapter][section];

.. and the AA would make sure the element is created if it didn't 
exist before. I know I could create a function for that but I am 
looking for a standard approach that already exists.

Thanks!
André
Nov 26 2015
next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Thursday, 26 November 2015 at 17:27:34 UTC, André wrote:
 Hi,

 I have a maybe trivial question on how to insert or update a 
 given entry in a multidimensional AA. So I have this AA:

    /// language, chapter, section. Content is a magic struct
    Content[int][string][string] contentAA;

 In some part of my code I want to either add a complete new 
 entry or update an existing one. I just came up with this 
 solution but it seems complex to me:

    string language, chapter;
    int section;
    Content* content;
    if (auto l = language in contentAA) {
        if (auto c = chapter in *l) {
               content = section in *c;
        }
    }
    if (!content) {
        contentAA[language][chapter][section] = Content();
        content = &contentAA[language][chapter][section];
    }
    /// work with content regardless whether it is updated or 
 newly inserted

 My question now is: is there some more elegant solution to 
 achieve this? Something like in C++ when you have std::map's of 
 std::map's and just access the elements and the entry is 
 created implicitly? Basically I would want to just have this 
 line working out of the box:

    content = &contentAA[language][chapter][section];

 .. and the AA would make sure the element is created if it 
 didn't exist before. I know I could create a function for that 
 but I am looking for a standard approach that already exists.

 Thanks!
 André
AA are weird in that AFAIK you need to "initialise" them before you try to look suff up in them else they crash. i.e. int[string] foo; // auto e = "1" in foo; // crash AA not initialised foo[ "blah"] = 0; foo.remove("blah"); auto e = "1" in foo; //doesn't crash have you tried using aa.get(key,default);? i.e. contentAA.get(language,"english").get(section, "somedefault").get(section,0); other than that are you likey to have missing sections? (i.e. do you need an AA for section or can you just use an array?) similarly; does chapter need to be indexed by string? can you get away with indexing by chapter number and storing an array of chapter names and looking that up when needed? Nic
Nov 26 2015
next sibling parent Jack Applegame <japplegame gmail.com> writes:
On Friday, 27 November 2015 at 04:21:41 UTC, Nicholas Wilson 
wrote:
 AA are weird in that AFAIK you need to "initialise" them before 
 you try to look suff up in them else they crash. i.e.
 int[string] foo;
 // auto e = "1" in foo; // crash AA not initialised
 foo[ "blah"] = 0;
 foo.remove("blah");
 auto e = "1" in foo; //doesn't crash
It's not true. "Not initalzed" AA s just empty AA. http://dpaste.dzfl.pl/82b38a2ad504
Nov 27 2015
prev sibling parent =?UTF-8?B?QW5kcsOp?= <Andre nospam.org> writes:
On Friday, 27 November 2015 at 04:21:41 UTC, Nicholas Wilson 
wrote:
 AA are weird in that AFAIK you need to "initialise" them before 
 you try to look suff up in them else they crash. i.e.
 int[string] foo;
 // auto e = "1" in foo; // crash AA not initialised
 foo[ "blah"] = 0;
 foo.remove("blah");
 auto e = "1" in foo; //doesn't crash

 have you tried using aa.get(key,default);?
 i.e. contentAA.get(language,"english").get(section, 
 "somedefault").get(section,0);
That doesn't work for my use case unfortunately. The object I am getting of this call isn't the one I would like update at [language][chapter][section]. I really need a pointer or reference to the object that is held my the map.
 other than that are you likey to have missing sections? (i.e. 
 do you need an AA for section or can you just use an array?)
 similarly; does chapter need to be indexed by string? can you 
 get away with indexing by chapter number and storing an array 
 of chapter names and looking that up when needed?
Chapter is indeed the chapter's title. But you are right - the sections could be an usual array. Still the problem still is the same for the first two dimensions.
Nov 28 2015
prev sibling parent reply Jack Applegame <japplegame gmail.com> writes:
On Thursday, 26 November 2015 at 17:27:34 UTC, André wrote:
 My question now is: is there some more elegant solution to 
 achieve this? Something like in C++ when you have std::map's of 
 std::map's and just access the elements and the entry is 
 created implicitly?
No. But you can create a wrapper: http://dpaste.dzfl.pl/80ad84e8f010
Nov 27 2015
parent =?UTF-8?B?QW5kcsOp?= <Andre nospam.org> writes:
On Friday, 27 November 2015 at 08:53:18 UTC, Jack Applegame wrote:
 On Thursday, 26 November 2015 at 17:27:34 UTC, André wrote:
 My question now is: is there some more elegant solution to 
 achieve this? Something like in C++ when you have std::map's 
 of std::map's and just access the elements and the entry is 
 created implicitly?
No. But you can create a wrapper: http://dpaste.dzfl.pl/80ad84e8f010
Thank you very much! That's a nice piece of code. I was looking for something like that in the standard library - to me it seems like something others might need regularly too. Regards, André
Nov 28 2015