# collections

The collections module is a collection manipulation module that offers functions
to work with lists in Cypher queries, allowing operations like filtering,
sorting, and modification for efficient data handling.

Functions in the collection are called inline, while the procedure as called
using the `CALL` subclause. 

| Trait               | Value                                                 |
| ------------------- | ---------- |
| **Module type**     | util       |
| **Implementation**  | C++        |
| **Graph direction** | directed   |
| **Edge weights**    | weighted   |
| **Parallelism**     | sequential |

## Functions

If a function requires elements to be comberable, `Path`, `List` and `Map` are
uncomparable. 

Only `Numeric` data types can be used in `sum()` and `avg()` functions, so only
`Int` and `Double` data types are allowed.

### Handling `NULL` values

Passing `NULL` as a whole list (or scalar) argument no longer raises an
argument-validation error. Each function returns a defined result:

| Function | Result when a list argument is `NULL` |
| --- | --- |
| `sum()`, `sum_longs()`, `avg()`, `min()`, `max()`, `to_set()`, `pairs()` | `null` |
| `union()`, `union_all()`, `disjunction()` | the other list; `null` when both are `NULL` |
| `remove_all()`, `subtract()` | `null` when the first list is `NULL`; the first list when the second is `NULL` |
| `intersection()`, `sort()`, `flatten()`, `duplicates()` | empty list `[]` |
| `contains()`, `contains_all()`, `contains_sorted()` | `false` |
| `frequencies_as_map()` | empty map `{}` |
| `split()`, `partition()` | no rows |

`NULL` elements inside a list are handled per function:

- `min()` and `max()` skip `NULL` elements; a list containing only `NULL` values returns `null`.
- `contains()` and `contains_all()` never match a `NULL` search value (`NULL = NULL` is not true), so searching for `NULL` returns `false`.
- `split()` treats a `NULL` delimiter as matching nothing and returns the whole list as a single part; `NULL` list elements are kept.
- `frequencies_as_map()` counts `NULL` elements under the `"NO_VALUE"` key.
- `flatten()`, `pairs()`, `to_set()`, `union()`, `union_all()`, `remove_all()`, `intersection()`, `disjunction()`, `subtract()` and `duplicates()` keep `NULL` elements as ordinary values.
- `sum()`, `sum_longs()`, `avg()`, `sort()` and `contains_sorted()` still reject a list that contains a `NULL` element; `contains_sorted()` also rejects a `NULL` search value, and `partition()` still rejects a `NULL` size.

For example, a `NULL` argument returns the defined result instead of erroring:

```cypher
RETURN collections.sum(null) AS sum, collections.sort(null) AS sorted;
```

```plaintext
+----------------------------+
| sum        | sorted        |
+----------------------------+
| null       | []            |
+----------------------------+
```

### `sort()`

Sorts the elements of an input list if they are of the same data type. For the input
list to be sorted, its elements must be comparable and of the same type.

> **Info**
>
> This function is equivalent to **apoc.coll.sort**.

#### Input:

- `coll: List[Any]` ➡ List of elements that need to be sorted.

#### Output:

- `List[Any]` ➡ The list of sorted elements.

#### Usage:

The following query will sort elements of the list:

```cypher
RETURN collections.sort([1, 4, 2.3, -5]) AS sorted;
```

```plaintext
+----------------------------+
| sorted                     |
+----------------------------+
| [-5, 1, 2.3, 4]            |
+----------------------------+
```

### `contains_sorted()`

Verifies the presence of a certain element in a sorted list. If an unsorted list
is passed, there is no guarantee that the result will be correct. For the input
list to be sorted, its elements must be comparable and of the same type.

> **Info**
>
> This function is equivalent to **apoc.coll.containsSorted**.

#### Input:

- `coll: List[Any]` ➡ The target list where the element is searched for.
- `value: Any` ➡ The element searched for.

#### Output:

- `bool` ➡ `true` if the element was found, `false` otherwise.

#### Usage:

The following query will check if number 2 is contained within the list:

```cypher
RETURN collections.contains_sorted([1, 2, 3.3, 4.4, 5], 2) AS contains;
```

```plaintext
+----------------------------+
| contains                   |
+----------------------------+
| true                       |
+----------------------------+
```

### `union()`

Unites two lists into one, eliminating duplicates.

> **Info**
>
> This function is equivalent to **apoc.coll.union**.

#### Input:

- `first: List[Any]` ➡ The first list of elements.
- `second: List[Any]` ➡ The second list of elements.

#### Output:

- `List[Any]` ➡ The union of the two input lists.

#### Usage:

The following query will merge two list into one, leaving only unique elements: 

```cypher
RETURN collections.union([0, 1, 2, 3], [2, 2, 3, 4, 5]) AS union;
```

```plaintext
+----------------------------+
| union                      |
+----------------------------+
| [4, 3, 5, 2, 1, 0]         |
+----------------------------+
```

### `union_all()`

Returns the union of two input lists, including duplicates.

> **Info**
>
> This function is equivalent to **apoc.coll.unionAll**.

#### Input:

- `first: List[Any]` ➡ The first list.
- `second: List[Any]` ➡ The second list.

#### Output:

- `List[Any]` ➡ The union of two lists, including duplicates.

#### Usage:

The following query will merge two lists into one:

```cypher
RETURN collections.union_all([1,1,2,3],[3,"a","b","c"]) AS return_list;
```

```plaintext
+---------------------------------------------------------+
| return_list                                             |
+---------------------------------------------------------+
| [1,1,2,3,3,"a","b","c"]                                 |
+---------------------------------------------------------+
```

### `remove_all()`

Removes defined elements from the input list. If a non-existent element is
passed in the list, it will be ignored.

> **Info**
>
> This function is equivalent to **apoc.coll.removeAll**.

#### Input:

- `first: List[Any]` ➡ The list from which elements need to be removed.
- `second: List[Any]` ➡ The list of elements that need to be removed.

#### Output:

- `List[Any]` ➡ The input list after removing the specified elements.

#### Usage:

The following query will remove 1, 2, 3 and 7 from a list of numbers from 1-5. 

```cypher
RETURN collections.remove_all([1, 2, 3, 4, 5], [1, 2, 3, 7]) AS removed;
```

Only numbers 4 and 5 remain, while the number 7 was ignored as it does not exist
in the input list.

```plaintext
+----------------------------+
| removed                    |
+----------------------------+
| [4, 5]                     |
+----------------------------+
```

### `contains()`

Verifies the existence of an input value in an input list.

> **Info**
>
> This function is equivalent to **apoc.coll.contains**.

#### Input:

- `coll: List[Any]` ➡ The input list checked for a certain value.
- `value: Any` ➡ The input value searched in the list.

#### Output:

- `boolean` ➡ `true` if the value is present in the list, otherwise `false`.

#### Usage:

The following query will check if "e" is contained within the list:

```cypher
RETURN collections.contains([1,2,3], "e") AS output;
```

```plaintext
+---------------------------------------------------------+
| output                                                  |
+---------------------------------------------------------+
| false                                                   |
+---------------------------------------------------------+
```

### `contains_all()`

Checks if a list contains all the values from another list.

> **Info**
>
> This function is equivalent to **apoc.coll.containsAll**.

#### Input:

- `coll: List[Any]` ➡ The target list used for searching values.
- `values: List[Any]` ➡ Values searched for in the target list.

#### Output:

- `boolean` ➡ `true` if all the elements specified in the `values`
  parameter are contained in the `collection` list.

#### Usage:

The following query will check if all the unique elements from a list are
contained within a target list:

```cypher
RETURN collections.contains_all([1, 2, 3, "pero"], [1, 1, 1, 1, 2, 3]) AS contained;
```

```plaintext
+---------------------------------------------------------+
| contained                                               |
+---------------------------------------------------------+
| true                                                    |
+---------------------------------------------------------+
```

### `intersection()`

Returns the unique intersection of two lists.

> **Info**
>
> This function is equivalent to **apoc.coll.intersection**.

#### Input:

- `first: List[Any]` ➡ The first list.
- `second: List[Any]` ➡ the second list.

#### Output:

- `List[Any]` ➡ The unique intersection of two lists.

#### Usage:

The following query will return the unique elements present in both lists:

```cypher
RETURN collections.intersection([1, 1, 2, 3, 4, 5], [1, 1, 3, 5, 7, 9]) AS intersection;
```

```plaintext
+---------------------------------------------------------+
| intersection                                            |
+---------------------------------------------------------+
| [3, 5, 1]                                               |
+---------------------------------------------------------+
```

### `disjunction()`

Returns the disjunction (symmetric difference) of two lists: the unique elements
present in exactly one of the lists. The order of the result is not guaranteed.

> **Info**
>
> This function is equivalent to **apoc.coll.disjunction**.

#### Input:

- `list1: List[Any]` ➡ The first list.
- `list2: List[Any]` ➡ The second list.

#### Output:

- `List[Any]` ➡ The unique elements found in only one of the two lists.

#### Usage:

The following query will return the elements present in only one of the lists:

```cypher
RETURN collections.disjunction([1, 2, 3, 4, 5], [3, 4, 5]) AS disjunction;
```

```plaintext
+---------------------------------------------------------+
| disjunction                                             |
+---------------------------------------------------------+
| [1, 2]                                                  |
+---------------------------------------------------------+
```

### `subtract()`

Returns the first list as a set with all elements of the second list removed. The
result is deduplicated and its order is not guaranteed.

> **Info**
>
> This function is equivalent to **apoc.coll.subtract**.

#### Input:

- `list1: List[Any]` ➡ The list to subtract from.
- `list2: List[Any]` ➡ The list of elements to remove.

#### Output:

- `List[Any]` ➡ The unique elements of the first list that are not present in the second list.

#### Usage:

The following query will remove the elements of the second list from the first:

```cypher
RETURN collections.subtract([1, 2, 3, 4, 5, 6, 6], [3, 4, 5]) AS subtracted;
```

```plaintext
+---------------------------------------------------------+
| subtracted                                              |
+---------------------------------------------------------+
| [1, 2, 6]                                               |
+---------------------------------------------------------+
```

### `duplicates()`

Returns the values that appear more than once in a list, each reported a single
time, in the order in which the duplicate is first observed.

> **Info**
>
> This function is equivalent to **apoc.coll.duplicates**.

#### Input:

- `coll: List[Any]` ➡ The input list.

#### Output:

- `List[Any]` ➡ The values that occur more than once in the input list.

#### Usage:

The following query will return the values that appear more than once:

```cypher
RETURN collections.duplicates([1, 1, 2, 3, 3, 3]) AS duplicates;
```

```plaintext
+---------------------------------------------------------+
| duplicates                                              |
+---------------------------------------------------------+
| [1, 3]                                                  |
+---------------------------------------------------------+
```

### `flatten()`

Returns flattened list of inputs provided.

> **Info**
>
> This function is equivalent to **apoc.coll.flatten**.

#### Input:

- `list: List[Any]` ➡ The list used to flatten.

#### Output:

- `List[Any]` ➡ The list containing elements from the input list.

#### Usage:

The following query will flatten input list into same level:

```cypher
WITH [1] as nums,
      ["text", 2.5] as mixed,
      [true, false] as bools
WITH COLLECT(nums) + [mixed] + [bools] + COLLECT(null) as input_list
RETURN collections_module.flatten(input_list) as result
```

```plaintext
+---------------------------------------------------------+
| result                                                  |
+---------------------------------------------------------+
| [1, "text", 2.5, True, False]  |
+---------------------------------------------------------+
```

### `frequencies_as_map()`

Returns a map of frequencies of the items in the collection.

> **Info**
>
> This function is equivalent to **apoc.coll.frequenciesAsMap**.

#### Input:

- `coll: List[Any]` ➡ The collection whose item frequencies will be counted.

#### Output:

- `Map[String, Integer]` ➡ A map where keys are string representations of the
items, and values are their frequencies.

#### Usage:

The following query will count the frequency of each element in the list:

```cypher
RETURN collections.frequencies_as_map([1, 1, 2, 1, 3, 4, 1, 3]) AS result;
```

```plaintext
+---------------------------------------------------------+
| result                                                  |
+---------------------------------------------------------+
| {"1": 4, "2": 1, "3": 2, "4": 1}                        |
+---------------------------------------------------------+
```

### `pairs()`

Creates pairs of neighbor elements within an input list.

> **Info**
>
> This function is equivalent to **apoc.coll.pairs**.

#### Input:

- `list: List[Any]` ➡ The list used to create pairs.

#### Output:

- `List[Any]` ➡ The list containing pairs of elements from the input list.

#### Usage:

The following query will create pairs of neighbor elements:

```cypher
RETURN collections.pairs([3, "s", 4.4, [1, 2]]) AS pairs;
```

```plaintext
+---------------------------------------------------------+
| pairs                                                   |
+---------------------------------------------------------+
| [[3, "s"], ["s", 4.4], [4.4, [1, 2]], [[1, 2], null]]   |
+---------------------------------------------------------+
```

### `to_set()`

Converts the input list to a set.

> **Info**
>
> This function is equivalent to **apoc.coll.toSet**.

#### Input:

- `values: List[Any]` ➡ The list that will be converted into a set.

#### Output:

- `List[Any]` ➡ The set returned as an `mgp::List` data type.

#### Usage:

The following query will convert the input list into a set:

```cypher
RETURN collections.to_set([1,2,1,2,3]) AS result;
```

```plaintext
+---------------------------------------------------------+
| result                                                  |
+---------------------------------------------------------+
| [3,2,1]                                                 |
+---------------------------------------------------------+
```

### `sum()`

Calculates the sum of listed elements if they are of the same type and can be
summed (the elements need to be numerics). Listing elements of different data
types, or data types that are impossible to sum, will throw an exception.

> **Info**
>
> This function is equivalent to **apoc.coll.sum**.

#### Input:

- `numbers: List[Any]` ➡ The list of elements that will be summed up.

#### Output:

- `double` ➡ The sum of all elements from the input list.

#### Usage:

The following query will sum the elements of the input list: 

```cypher
CREATE (:A {id:5});
MATCH (a:A) 
RETURN collections.sum([1, 2.3, -4, a.id]) AS sum;
```

```plaintext
+----------------------------+
| sum                        |
+----------------------------+
| 4.3                        |
+----------------------------+
```
### `sum_longs()`

Calculates the sum of list elements casted to integers. The initial list
elements have to be `Numeric` data type, or an exception is thrown.

> **Info**
>
> This function is equivalent to **apoc.coll.sumLongs**.

#### Input:

- `numbers: List[Any]` ➡ The list of numbers.

#### Output:

- `integer` ➡ The sum of listed elements.

#### Usage:

The following query will sum the integers in the list:

```cypher
RETURN collections.sum_longs([1.9, 1.9]) AS sum;
```

```plaintext
+---------------------------------------------------------+
| sum                                                     |
+---------------------------------------------------------+
| 2                                                       |
+---------------------------------------------------------+
```

### `avg()`

Calculates the average of listed elements if they are of the same type and can
be summed (the elements need to be numerics). Listing elements of different data
types, or data types that are impossible to sum, will throw an exception.

> **Info**
>
> This function is equivalent to **apoc.coll.avg**.

#### Input:

- `numbers: List[Any]` ➡ The list of numbers.

#### Output:

- `double` ➡ The average of listed elements.

#### Usage:

The following query will calculate the average of elements in the list: 

```cypher
RETURN collections.avg([5, 5, 6, 7, -5]) AS average;
```

```plaintext
+---------------------------------------------------------+
| average                                                 |
+---------------------------------------------------------+
| 3.6                                                     |
+---------------------------------------------------------+
```

### `max()`

The procedure returns the element of the maximum value from the input list.

> **Info**
>
> This function is equivalent to **apoc.coll.max**.

#### Input:

- `values: List[Any]` ➡ The input list where an element of the maximum value must be found.

#### Output:

- `Any` ➡ The element of the maximum value from the input list.

#### Usage:

Use the following procedure to get the element of the maximum value:

```cypher
RETURN collections.max([-1, -2, -3.3]) AS max;
```

```plaintext
+----------------------------+
| max                        |
+----------------------------+
| -1                         |
+----------------------------+
```

### `min()`

Finds the element of the minimum value in an input list. Listing elements of
different data types, or data types that are impossible to compare, will throw an
exception.

> **Info**
>
> This function is equivalent to **apoc.coll.min**.

#### Input:

- `values: List[Any]` ➡ The input list where an element of the minimum value must be found.

#### Output:

- `Any` ➡ The element of the minimum value from the input list.

#### Usage:

Use the following query to find the element of the minimum value in the list:

```cypher
RETURN collections.min([1,2,3]) AS min;
```

```plaintext
+---------------------------------------------------------+
| min                                                     |
+---------------------------------------------------------+
| 1                                                       |
+---------------------------------------------------------+
```

## Procedures

### `split()`

Splits the provided list based on a specified delimiter. Returns a series of
sublists generated by breaking the original list wherever the delimiter is
encountered. The delimiter itself is not included in the resulting sublists.

> **Info**
>
> This procedure is equivalent to **apoc.coll.split**.

#### Input:

- `subgraph: Graph` (**OPTIONAL**) ➡ A specific subgraph, which is an [object of type Graph](https://memgraph.com/docs/advanced-algorithms/run-algorithms#run-procedures-on-subgraph) returned by the `project()` function, on which the algorithm is run. 
If subgraph is not specified, the algorithm is computed on the entire graph by default.
- `inputList: List[Any]` ➡ The input list that needs to be split.
- `delimiter: Any` ➡ The element that determines the split point.

#### Output:

- `split: List[Any]` ➡ Sublists of the original list.

#### Usage:

Use the following query to split the list using a 0 as a delimiter:

```cypher
CALL collections.split([2, 4, "0", 0, 3.3, 9, 0, 5], 0)
YIELD split
RETURN split;
```

```plaintext
+----------------------------+
| split                      |
+----------------------------+
| [2, 4, "0"]                |
+----------------------------+
| [3.3, 9]                   |
+----------------------------+
| [5]                        |
+----------------------------+
```

### `partition()`

Partitions the input list into sub-lists of the specified `partition_size`.

> **Info**
>
> This procedure is equivalent to **apoc.coll.partition**.

#### Input:

- `subgraph: Graph` (**OPTIONAL**) ➡ A specific subgraph, which is an [object of type Graph](https://memgraph.com/docs/advanced-algorithms/run-algorithms#run-procedures-on-subgraph) returned by the `project()` function, on which the algorithm is run. 
If subgraph is not specified, the algorithm is computed on the entire graph by default.
- `list: List[Any]` ➡ The list that will be partitioned.
- `partition_size: integer` ➡ The size of the sub-lists.

#### Output:

- `result: List[Any]` ➡ The partitioned sub-lists.

#### Usage:

Use the following query to partitional the list into two elements.

```cypher
CALL collections.partition([1,2,3,4,5,6],2)
YIELD result
RETURN result;
```

```plaintext
+---------------------------------------------------------+
| result                                                  |
+---------------------------------------------------------+
| [1,2]                                                   |
+---------------------------------------------------------+
| [3,4]                                                   |
+---------------------------------------------------------+
| [5,6]                                                   |
+---------------------------------------------------------+
```
