Packages

A high-performance, extensible expression evaluation engine for Elixir.

Current section

Files

Jump to
excellerate lib excellerate functions general take.ex
Raw

lib/excellerate/functions/general/take.ex

defmodule ExCellerate.Functions.General.Take do
@moduledoc """
Extracts rows, columns, or both from a list or 2D array.
Mimics the spreadsheet `TAKE` function. Positive counts take from the
beginning; negative counts take from the end. Pass `null` to skip a
dimension.
## Examples
take(data, 3) → first 3 rows
take(data, -3) → last 3 rows
take(data, null, 2) → first 2 columns (all rows)
take(data, 3, 2) → first 3 rows, first 2 columns
take(data, -2, -2) → last 2 rows, last 2 columns
"""
@behaviour ExCellerate.Function
import ExCellerate.Functions.Guards
@impl true
def name, do: "take"
@impl true
def arity, do: 2..3
@impl true
def call([list, rows]) do
ensure_list!(list, name())
take_rows(list, rows)
end
def call([list, rows, cols]) do
ensure_list!(list, name())
list |> take_rows(rows) |> take_cols(cols)
end
defp take_rows(list, nil), do: list
defp take_rows(_list, 0), do: []
defp take_rows(list, n) do
ensure_integer!(n, name())
len = length(list)
count = min(abs(n), len)
if n > 0 do
Enum.take(list, count)
else
Enum.drop(list, len - count)
end
end
defp take_cols(list, nil), do: list
defp take_cols(list, n) do
ensure_integer!(n, name())
Enum.map(list, fn row ->
ensure_list!(row, name())
width = length(row)
count = min(abs(n), width)
if n > 0 do
Enum.take(row, count)
else
Enum.drop(row, width - count)
end
end)
end
end