# `Feel.Runtime.EqualItems`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/runtime/equal_items.ex#L1)

Which items of a list are the first of several that are equal, and which are equal to one before them
([`occurrences/1`](Feel.Runtime.EqualItems.html#occurrences/1)), and the list without the items that are equal to one that was kept
([`distinct/1`](Feel.Runtime.EqualItems.html#distinct/1)), without comparing
every pair.

Two items are equal when `Feel.Runtime.Compare.equal/2` says `{:ok, true}`: two that cannot be compared are not equal,
and nothing is reported of them. Asking that of every pair of a list of `n` items is `n * n / 2` comparisons, and a run
may build a list of `max_list_length` items. An item that has a **key**, a term that two items share exactly when they
are equal, is told from the others by it, in a map: each item is read once.

| Kind | Key |
| ---- | --- |
| number | the sign, the coefficient without the zeros at its end, and the exponent that goes with it (`1` and `1.00` are equal), or `0` |
| string, boolean, `null` | the value |
| date | the year, month and day |
| years and months duration | the months |
| days and time duration | the key of the seconds, as for a number |
| time, date and time | the whole seconds (the resolution of `=`, D-54) of the local time if it has no time offset or zone, and of the instant if it has one (`Feel.Runtime.Temporal.seconds/1`) |
| list | the keys of the items, in order |
| context | the keys of the values by name: the order of the entries is not a part of it |
| range | the keys of the endpoints, and whether each is included, and how the range was written (D-61) |

A list, context or range has a key if every value in it has one, to any depth. The values that have none are of three
sorts, and each is dealt with as `Compare.equal/2` would deal with it:

  * **A value of no kind** (`Feel.Runtime.Kind`: a float or an atom that a host bound) is not equal to any value,
    itself included, for it cannot be compared. That is known without a comparison. A range that holds one is the
    same. A list or a context that holds one is not equal to a value that is not the same term, or does not have the
    same terms in it, and is equal to one that does (`Compare.equal/2`, D-168): it is compared with the others of its
    sort, as a function is.
  * **A function** is equal to a function that is the same term. The term holds the bindings it was written in, so it
    is not hashed: it is compared with the others of its sort, as is a list, context or range that holds one.
  * **A time or a date and time**, if the list has both ones with a time offset or a zone and ones with none. A time
    with a zone is equal to another by their instants, and one with none to either by its local fields, so
    `10:00:00+01:00` is equal to `10:00:00`, and that is equal to `10:00:00Z`, and the first is not equal to the third:
    no key is shared by all that are equal. Such a value is compared with the others of its sort, as is a list, context
    or range that holds one. A list that has the one sort of times only has a key for each.

The items that are compared are compared in pairs, `n * n / 2` for `n` of them, and with each other only: an item that
has a key is never equal to one without, since the two are not of one kind or have a part that is not. So a list of
functions is as long to work through as ever it was, and a list of numbers with one function in it is not.

**A term that is not a value of its kind** has no key and may be equal to a value that has one (a duration whose
months are not an integer, `1.0 == 1`; a date of another calendar than the ISO one). One such term anywhere in the
list makes it compared in pairs, all of it, so that the answer is the one of `Compare.equal/2` for any list.

# `distinct`

```elixir
@spec distinct([Feel.Value.t()]) :: [Feel.Value.t()]
```

The items that are not equal to an item that was kept before them: the first of each group of equal items, in order.

It is the items of `occurrences/1` that are not `:again`, but for the times that have no key, and so are compared: an
item is left out for an item that was **kept**, and not for one that was left out. With `a` and `b` equal, and `b` and
`c`, and `a` and `c` not equal (a time without a zone, one with an offset, and one with another), `[a, b, c]` has `a`
and `c`, where `c` is `:again` for `occurrences/1`, being equal to `b`.

    iex> Feel.Runtime.EqualItems.distinct([Decimal.new(1), nil, Decimal.new("1.0"), nil, 1.5, 1.5])
    [Decimal.new(1), nil, 1.5, 1.5]
    iex> {:ok, floating} = Feel.Value.Time.parse("10:00:00")
    iex> {:ok, plus_one} = Feel.Value.Time.parse("10:00:00+01:00")
    iex> {:ok, utc} = Feel.Value.Time.parse("09:00:00Z")
    iex> Feel.Runtime.EqualItems.distinct([floating, plus_one, utc]) == [floating, utc]
    true

# `occurrences`

```elixir
@spec occurrences([Feel.Value.t()]) :: [:alone | :first | :again]
```

What each item is, in order: `:again` if an item before it is equal, else `:first` if an item after it is, else
`:alone`. So `:first` and `:alone` items are the distinct values of the list, and the `:first` ones those of them that
occur more than once.

    iex> numbers = [Decimal.new(1), Decimal.new("2.0"), Decimal.new("1.00"), Decimal.new(3)]
    iex> Feel.Runtime.EqualItems.occurrences(numbers)
    [:first, :alone, :again, :alone]
    iex> Feel.Runtime.EqualItems.occurrences([nil, "a", nil])
    [:first, :alone, :again]
    iex> Feel.Runtime.EqualItems.occurrences([1.5, 1.5])
    [:alone, :alone]

---

*Consult [api-reference.md](api-reference.md) for complete listing*
