indexing
===============================================================================

%% An `index` is a way to access elements of a data structure, such as arrays, matrices, or tables, using specific criteria or positions.

1. Introduction
-------------------------------------------------------------------------------

There are various ways to access elements within data structures in Mech. The most common methods are:

- **Regular Indexing** - Accessing elements using specific integer positions.
- **Matrix Slicing** - Accessing multiple elements at once using ranges or entire rows/columns.
- **Logical Indexing** - Accessing elements based on boolean conditions.
- **Dot Indexing** - Accessing fields or properties of structured data types.

2. Matrix Slicing
-------------------------------------------------------------------------------

Slicing allows you to access multiple elements at once, either entire rows or columns, or specific ranges of rows and columns.

The `:` operator can be used to access entire rows or columns:

You can slice it in various ways. For a matrix x with `N` rows and `M` columns, the following indexing operations are valid:

| Syntax              | Description                        | Resulting Size   |
|---------------------|------------------------------------|------------------|
| {{x[:]}}              | Slice all elements                 | `[N*M x 1]`      |
| {{x[1,:]}}            | Slice a row                        | `[1 x M]`        |
| {{x[:,2]}}            | Slice a column                     | `[N x 1]`        |
| {{x[1..=2,:]}}        | Slice a range of rows              | `[2 x M]`        |
| `x[[1,3],:]`        | Slice specific rows                | `[2 x M]`        |
| `x[[1,3],[1,3]]`    | Slice specific rows and columns    | `[2 x 2]`        |
| `x[[1 1 2 2],:]`    | Slice the rows multiple times      | `[4 x M]`        |

For more, see the [`matrix`](/reference/matrix.mec#Slicing) documentation.

3. Logical Indexing
-------------------------------------------------------------------------------

A logical index is a boolean array (`true` / `false`) of the same size
as the data being indexed. Elements corresponding to `true` are selected; those
corresponding to `false` are ignored.

```mech:logical
x := [ 1  -2   3
       0   5  -1 
       1   0   0 ]
```

| Expression    | Description            | Result              |
|---------------|------------------------|---------------------|
| `x[x > 0]`    | All positive elements  | `[1, 3, 5]`         |
| `x[x < 0]`    | All negative elements  | `[-2, -1]`          |
| `x[x == 0]`   | All zero elements      | `[0 0 0]`           |
| `x[x != 0]`   | All non-zero elements  | `[1, -2, 3, 5, -1]` |

Logical indexing can also be applied per row or per column by using logical
vectors.

```mech:logical
rows := [true, false]
cols := [false, true, true]
```

| Syntax         | Description                            | Resulting Size |
|----------------|----------------------------------------|----------------|
| `x[rows, :]`   | Select rows where `rows` is `true`     | `[1 x M]`      |
| `x[:, cols]`   | Select columns where `cols` is `true`  | `[N x 2]`      |
| `x[rows,cols]` | Select rows and columns logically      | `[1 x 2]`      |

You can combine logical conditions using logical operators:

```mech:logical
x[(x > 0) && (x < 4)]
```

This selects `[1, 3]`, the elements greater than `0` and less than `4`.

Logical indexing can be combined with regular indexing for more complex selections. For example, to select positive elements from the first two rows:

```mech:logical
x[1..=2, :][x[1..=2, :] > 0]
```

4. Dot Indexing
-------------------------------------------------------------------------------

Dot indexing is used to access fields or properties of structured data types, such as records or objects.

```mech:dot-indexing
person := {
  name: "Alice",
  age: 30,
  address: {
    street: "123 Red Queen St",
    city: "Wonderland"
  }
}
```

To access the fields of the `person` record, you can use dot notation:

| Expression            | Description                  | Result               |
|-----------------------|------------------------------|----------------------|
| `person.name`         | Access the `name` field      | `"Alice"`            |
| `person.age`          | Access the `age` field       | `30`                 |
| `person.address.city` | Access the `city` field      | `"Wonderland"`       |

Dot indexing can also be used with tables:

```mech:dot-indexing
employees := 
| name<string> age<u8> position<string> |
| "Bob"        28      "Engineer"     |
| "Carol"      34      "Manager"      |
| "Dave"       25      "Intern"       |
| "Eve"        30      "Designer"     |
```

You can use dot indexing to access columns in the table:

```mech:dot-indexing
employees.name
```

This returns the `name` column: `["Bob", "Carol", "Dave", "Eve"]`.