Re: How to use associative arrays in Ada 2005?



On Thu, 2006-11-23 at 11:27 -0800, snoopysalive wrote:


The statement "Ages.Insert("family name",Insert("name",23));" doesn't
work. So, how is it possible to do something like this in C++:
"...
map<string, map<string,int>> ages;
ages["family name"]["name"] = 23;
..."

I think that in this case the Ada.Containers requirement
of being minimal building blocks applies. And probably also
the principle of query/command separation, which is not followed
by std::map::operator[]. [] does many things at the same time,
hence it is not minimal.

If I remember Matt's tutorial correctly, there is an example showing how
to manipulate items in containers in situ. Barnes' book has this, too.

If the elements in a map are containers themselves (or are
otherwise big), you may want to use Update_Element.

If you have +-----------+
+--> | ... |
+-------------+ | +-----------+
| ... | --+ | ... | +--> ...
+-------------+ +----------+ |
| family name | --> | ... | ---+
+-------------+ +----------+
| ... | | name | ------> 23
+----------+
| ... |

That is in order to manipulate one of the 2nd level maps,
you could either:

- Get the element at key "family name", which is a map.
This creates a copy of the map.
- Manipulate the copied map.
- Put the map back to where it had been (at key "family name"),
again copying.

Or,

- Get a cursor for the element at key "family name".
- Define a subprogram that manipulates the 2nd level map
(the one containing "name" as key).
- Call Update_Element with the cursor and the subprogram.

with Ada.Text_IO,
Ada.Strings.Hash,
Ada.Containers.Indefinite_Hashed_Maps;
use Ada.Text_IO,
Ada.Strings,
Ada.Containers;

procedure book2 is
package Str_Int_Maps is
new Ada.Containers.Indefinite_Hashed_Maps
(String,
Integer,
Ada.Strings.Hash,
"=");
use Str_Int_Maps;
package Str_Map_Maps is
new Ada.Containers.Indefinite_Hashed_Maps
(String,
Str_Int_Maps.Map,
Ada.Strings.Hash,
"=");

Ages : Str_Map_Maps.Map; -- That's the "hash of a hash"
Named_Age: Str_Int_Maps.Map;


-- life by population statistics:

Average: constant Natural := 80;
function Grow_Older(Now: Integer) return Integer is separate;
-- used to compute a new `Age` from `Now`

Age: Integer := 0;

procedure Set_Age(name: String; value: in out Str_Int_Maps.Map) is
begin
Named_Age.Include("name", Age); -- Note how `Age` is used here
end Set_Age;

begin
Ages.Insert("family name", Named_Age);

while Age < Average loop
Age := Grow_Older(Age);

--
Ages.Update_Element(position => Ages.Find("family name"),
process => Set_Age'access); -- in situ
end loop;
end book2;

This might seem like a lot, but once you have your setup, you
can reuse it, or write []-style wrappers, if you need them
etc.. Scope is important in this example, because the `Age`
variable is visible to Set_Age, and need not be passed around.


.



Relevant Pages