# Operations

## `AssociativeArray() -> Assoc`

```magma
Default: Any                    Default: 
```

Create the null associative array $A$ with no index universe. The first assignment to $A$ will determine its index universe. The optional parameter `Default := D` allows one to associate the default value $D$ to $A$ (so $A[x]$ will return $D$ if $x$ is not in the keys of $A$).

## `AssociativeArray(I): Str -> Assoc`

```magma
Default: Any                    Default: 
```

Create the empty associative array $A$ with index universe $I$. The optional parameter `Default := D` allows one to associate the default value $D$ to $A$ (so $A[x]$ will return $D$ if $x$ is not in the keys of $A$).

## `A[x] := y: Assoc, Elt, Elt`

Set the value in $A$ associated with index $x$ to be $y$. If $x$ is not coercible into the current index universe $I$ of $A$, then an attempt is first made to lift the index universe of $A$ to contain both $I$ and $x$.

In a nested assignment such as `A[x][z] := y`, if $x$ is not in the keys of $A$ but a default value $D$ was specified when $A$ was created, then $A[x]$ is first set to $D$ and the assignment then proceeds on that value. Thus arrays of arrays may be built up without initializing each level explicitly (see the example below).

## `A[x]: Assoc, Elt -> Elt`

Given an index $x$ coercible into the index universe $I$ of $A$, return the value associated with $x$. If $x$ is not in the keys of $A$, then: (1) if a default value $D$ was specified when $A$ was created, then $D$ is returned; (2) otherwise, an error is raised.

## `IsDefined(A, x): Assoc, Elt -> Bool, Elt`

Given an index $x$ coercible into the index universe $I$ of $A$, return whether $A[x]$ is currently defined, and if so, return also the value $A[x]$. This is the case if $x$ is in the keys of $A$ or $A$ has a default value.

## `IsInKeys(A, x): Assoc, Elt -> Bool, Elt`

Given an index $x$ coercible into the index universe $I$ of $A$, return whether $x$ is explicitly in the keys of $A$ and if so, return also the value $A[x]$.

## `Remove(~A, x): Assoc, Elt`

(Procedure.) Destructively remove the value indexed by $x$ from the array $A$. If $x$ is not present as an index, then nothing happens (i.e., an error is not raised).

## `Universe(A): Assoc -> Str`

Given an associative array $A$, return the index universe $I$ of $A$, in which the keys of $A$ currently lie.

## `# A: Assoc -> RngIntElt`

Given an associative array $A$, return the number of items stored in $A$.

## `Keys(A): Assoc -> SetEnum`

Given an associative array $A$, return the current keys of $A$ as a set. Warning: this constructs a new copy of the set of keys, so should only be called when that is needed; it is not meant to be used as a quick access function.

## `Values(A): Assoc -> List`

Given an associative array $A$, return the current values of $A$ as an unsorted list (a list is returned since the values need not lie in a fixed universe but may be of any type). Warning: this constructs a new copy of the list of values, so should only be called when that is needed; it is not meant to be used as a quick access function.

## `Example: Assoc Creation (ex-c3ad44)`

This example shows simple use of associative arrays. First we create an array indexed by rationals.

```magma
> A := AssociativeArray();
> A[1/2] := 7;
> A[3/8] := "abc";
> A[3] := 3/8;
> A[1/2];
7
> IsDefined(A, 3);
true 3/8
> IsDefined(A, 4);
false
> IsDefined(A, 3/8);
true abc
> Keys(A);
{ 3/8, 1/2, 3 }
> Values(A);
[* 7, abc, 3/8 *]
> for x in Keys(A) do x, A[x]; end for;
1/2 7
3/8 abc
3 3/8
> Remove(~A, 3/8);
> IsDefined(A, 3/8);
false
> Keys(A);
{ 1/2, 3 }
> Values(A);
[* 7, 3/8 *]
> Universe(A);
Rational Field

```

We repeat that an associative array can be indexed by elements of any structure. We now index an array by elements of the symmetric group $S_3$.

```magma
> G := Sym(3);
> A := AssociativeArray(G);
> v := 1; for x in G do A[x] := v; v +:= 1; end for;
> A;
Associative Array with index universe GrpPerm: G, Degree 3, Order 2 * 3
> Keys(A);
{
    (1, 3, 2),
    (2, 3),
    (1, 3),
    (1, 2, 3),
    (1, 2),
    Id(G)
}
> A[G!(1,3,2)];
3

```

The following shows how the parameter `Default` can be used when an associative array $A$ is created.

```magma
> A := AssociativeArray(: Default := []);
> x := 3; y := 5;
> Append(~A[x], y);
> assert A[x] eq [y];
> assert Keys(A) eq {x};
> assert Values(A) eq [* [ y ] *];
> IsDefined(A, x);
true [ 5 ]
> IsInKeys(A, x);
true [ 5 ]
> IsDefined(A, 4);
true []
> IsInKeys(A, 4);
false

```

Here we can append an element to $A[x]$ even when $x$ is not yet in the keys of $A$; in such a case, $A[x]$ is initially taken to be $[]$ and so can be appended to without error.

Since the default may itself be an associative array with a default, nested arrays may be built up in the same way, without initializing any of the intermediate levels.

```magma
> A := AssociativeArray(: Default := AssociativeArray(: Default := []));
> Append(~A[1][2], 3);
> Append(~A[1][2], 4);
> Append(~A[5][6], 7);
> A[1][2];
[ 3, 4 ]
> Keys(A);
{ 1, 5 }
> Keys(A[5]);
{ 6 }

```

An index is only added to the keys of $A$ when something is actually assigned to it, so simply reading a value leaves $A$ unchanged.

```magma
> A[9][9];
[]
> Keys(A);
{ 1, 5 }

```
