Files
n8n-openai-adapter/lib/list.ex
T
2012-05-13 15:33:57 +02:00

477 lines
9.8 KiB
Elixir

defmodule List do
@moduledoc """
Implements functions that only make sense for lists
and cannot be part of the Enum protocol. In general,
favor using the Enum API instead of List.
A decision was taken to delegate most functions to
Erlang's standard lib but following Elixir's convention
of receiving the target (in this case, a list) as the
first argument.
"""
@doc """
Simply invokes the Access protocol for the given list.
Check `Access.List` for more information.
"""
def access(list, access) when is_list(list) do
Access.List.access(list, access)
end
@doc """
Given a list of lists, concatenates the sublists into a single list.
## Examples
List.concat [[1,[2],3], [4], [5,6]]
#=> [1,[2],3,4,5,6]
"""
def concat(list) when is_list(list) do
Erlang.lists.append(list)
end
@doc """
Concatenates the list on the right with the list on the left.
This function produces the same result the `++` operator. The only difference
is a minor optimization: when the first list contains only one element, we
simply add it as a head to the second list.
## Examples
List.concat [1,2,3], [4,5,6]
#=> [1,2,3,4,5,6]
"""
def concat([h], elements) when is_list(elements) do
[h|elements]
end
def concat(list, elements) when is_list(list) and is_list(elements) do
list ++ elements
end
@doc """
Deletes the given item from the list. Returns a list without the item.
If the item occurs more than once in the list, just the first occurrence
is removed.
## Examples
List.delete([1,2,3], 1)
#=> [2,3]
"""
def delete(list, item) do
Erlang.lists.delete(item, list)
end
@doc """
Flattens the given `list` of nested lists. An optional
tail can be given that will be added at the end of
the flattened list.
## Examples
List.flatten [1,[[2],3]]
#=> [1,2,3]
List.flatten [1,[[2],3]], [4,5]
#=> [1,2,3,4,5]
"""
def flatten(list) do
Erlang.lists.flatten(list)
end
def flatten(list, tail) do
Erlang.lists.flatten(list, tail)
end
@doc """
Folds (reduces) the given list to the left with
a function. Requires an accumulator.
## Examples
List.foldl [5,5], 10, fn x, acc -> x + acc end
#=> 20
List.foldl [1,2,3,4], 0, fn x, acc -> x - acc end
#=> 2
"""
def foldl(list, acc, function) when is_list(list) and is_function(function) do
Erlang.lists.foldl(function, acc, list)
end
@doc """
Folds (reduces) the given list to the right with
a function. Requires an accumulator.
## Examples
List.foldr [1,2,3,4], 0, fn x, acc -> x - acc end
#=> -2
"""
def foldr(list, acc, function) when is_list(list) and is_function(function) do
Erlang.lists.foldr(function, acc, list)
end
@doc """
Reverses the given list. This function simply delegates
to `lists:reverse` which is implemented in C for performance.
## Examples
List.reverse [1,2,3]
#=> [3,2,1]
"""
defdelegate [reverse: 1], to: Erlang.lists
@doc """
Returns the last element in `list` or nil if the `list` is empty.
## Examples
List.last []
#=> nil
List.last [1]
#=> 1
List.last [1, 2, 3]
#=> 3
"""
def last([]), do: nil
defdelegate [last: 1], to: Erlang.lists
@doc """
Checks if the given `term` is included in the list.
This function simply delegates to `lists:member`
which is implemented in C for performance.
## Examples
List.member? [1,2,3], 1
#=> true
List.member? [1,2,3], 0
#=> false
"""
def member?(list, term) do
Erlang.lists.member(term, list)
end
@doc """
Receives a list of tuples and returns the first tuple
where the item at position `posistion` matches with the
given `item`.
## Examples
List.keyfind([a: 1, b: 2], :a, 1)
#=> { :a, 1 }
List.keyfind([a: 1, b: 2], 2, 2)
#=> { :b, 2 }
List.keyfind([a: 1, b: 2], :c, 1)
#=> nil
"""
def keyfind(list, item, position, default // nil) do
Erlang.lists.keyfind(item, position, list) || default
end
@doc """
Receives a list of tuples and returns true if there is
a tuple where the item at position `posistion` matches
with the given `item`.
## Examples
List.keymember?([a: 1, b: 2], :a, 1)
#=> true
List.keymember?([a: 1, b: 2], 2, 2)
#=> true
List.keymember?([a: 1, b: 2], :c, 1)
#=> false
"""
def keymember?(list, item, position) do
Erlang.lists.keymember(item, position, list)
end
@doc """
Receives a list of tuples and deletes the first tuple
where the item at position `posistion` matches with the
given `item`. Returns the new tuple.
## Examples
List.keydelete([a: 1, b: 2], :a, 1)
#=> [{ :b, 2 }]
List.keydelete([a: 1, b: 2], 2, 2)
#=> [{ :a, 1 }]
List.keydelete([a: 1, b: 2], :c, 1)
#=> [{ :a, 1 }, { :b, 2 }]
"""
def keydelete(list, item, position) do
Erlang.lists.keydelete(item, position, list)
end
@doc """
Returns a list of integers in the given range (both ends included when
possible). An optional step can be provided as well (defaults to 1).
If first > last and no step is provided, the numbers will be in descending
order.
## Examples
List.range 1, 3 #=> [1,2,3]
List.range 1, 8, 2 #=> [1,3,5,7]
List.range 1, 0 #=> []
List.range 3, 1 #=> [3,2,1]
List.range 5, 1, -2 #=> [5, 3, 1]
"""
def range(first, last, step // nil)
def range(first, last, step) when is_integer(first) and is_integer(last) and first <= last do
step = case step do
nil ->
Erlang.lists.seq(first, last, 1)
x when x < 0 ->
[]
_ ->
Erlang.lists.seq(first, last, step)
end
end
def range(first, last, step) when is_integer(first) and is_integer(last) and first > last do
step = case step do
nil ->
Erlang.lists.seq(first, last, -1)
x when x > 0 ->
[]
_ ->
Erlang.lists.seq(first, last, step)
end
end
@doc """
Sorts the list by comparing each term. For an alternative
sorting algorithm, check `Enum.qsort`.
## Examples
List.sort [3, 4, 2, 1, 7]
#=> [1, 2, 3, 4, 7]
"""
def sort(list) do
:lists.sort list
end
@doc """
Sorts the list according to an ordering function. fun(a, b) should
return true if `a` compares less than or equal to `b`, `false` otherwise.
## Examples
List.sort [3, 4, 2, 1, 7], fn a, b -> b <= a end
#=> [7, 4, 3, 2, 1]
"""
def sort(list, fun) do
:lists.sort fun, list
end
@doc """
Returns a list without duplicated items.
## Examples
List.uniq [1,2,3,2,1]
#=> [1,2,3]
"""
def uniq(list) when is_list(list) do
do_uniq(list, [])
end
@doc """
Duplicates the given element n times in a list.
## Examples
List.duplicate "hello", 3
#=> ["hello","hello","hello"]
List.duplicate [1,2], 2
#=> [[1,2],[1,2]]
"""
def duplicate(elem, n) do
Erlang.lists.duplicate(n, elem)
end
@doc """
Looks for a term in a list and returns its position.
If term is found in the first position, return 1.
If no terms not found in list, the return value is nil.
### Examples
List.find_index ['a'], 'b'
#=> nil
List.find_index ['a'], 'a'
#=> 1
"""
def find_index(list, term) do
index = Erlang.string.str(list, [term])
case index == 0 do
true -> nil
false -> index
end
end
@doc """
Wraps the argument in a list.
If the argument is already a list, returns the list.
If the argument is nil, returns an empty list.
## Examples
List.wrap [1,2,3] #=> [1,2,3]
"""
def wrap(list) when is_list(list) do
list
end
def wrap(nil) do
[]
end
def wrap(other) do
[other]
end
@doc """
Zips corresponding elements from two lists (or tuples) into one list of tuples. The
number of elements in the resulting list is equal to the length of the
shortest list among the given ones.
## Examples
List.zip [1, 2, 3], [4, 5, 6]
#=> [{1, 4}, {2, 5}, {3, 6}]
List.zip [1, 2], [4, 5, 6]
#=> [{1, 4}, {2, 5}]
"""
def zip(item1, item2) do
do_zip(to_list(item1), to_list(item2), [])
end
@doc """
Zips corresponding elements from each list in `list_of_lists`.
## Examples
List.zip [[1, 2], [3, 4], [5, 6]]
#=> [{1, 3, 5}, {2, 4, 6}]
List.zip [[1, 2], [3], [5, 6]]
#=> [{1, 3, 5}]
"""
def zip(list_of_lists) when is_list(list_of_lists) do
do_zip(list_of_lists, [])
end
@doc """
Unzips the given list of lists or tuples into separate lists and returns a
list of lists.
## Examples
List.unzip [{1, 2}, {3, 4}]
#=> [[1, 3], [2, 4]]
List.unzip [{1, :a, "apple"}, {2, :b, "banana"}, {3, :c}]
#=> [[1, 2, 3], [:a, :b, :c]]
"""
def unzip(list) when is_list(list) do
:lists.map tuple_to_list(&1), zip(list)
end
## Private
# uniq
defp do_uniq([h|t], acc) do
case Erlang.lists.member(h, acc) do
true ->
do_uniq(t, acc)
false ->
[h|do_uniq(t, [h|acc])]
end
end
defp do_uniq([], _acc) do
[]
end
# zip
defp do_zip([h1|t1], [h2|t2], acc) do
do_zip t1, t2, [{h1, h2}|acc]
end
defp do_zip(_, _, acc) do
reverse acc
end
defp do_zip(list, acc) do
converter = fn x, acc -> do_zip_each(to_list(x), acc) end
{mlist, heads} = :lists.mapfoldl converter, [], list
case heads do
nil ->
:lists.reverse acc
_ ->
do_zip mlist, [list_to_tuple(:lists.reverse(heads))|acc]
end
end
defp do_zip_each(_, nil) do
{ nil, nil }
end
defp do_zip_each([h|t], acc) do
{ t, [h|acc] }
end
defp do_zip_each([], _) do
{ nil, nil }
end
defp to_list(tuple) when is_tuple(tuple), do: tuple_to_list(tuple)
defp to_list(list) when is_list(list), do: list
end