exercism/elixir/matrix/lib/matrix.ex

61 lines
1.7 KiB
Elixir

defmodule Matrix do
defstruct ~w(rows columns)a
defp at(list, index), do: Enum.at(list, index - 1)
defp transpose(list), do: Enum.zip_with(list, &Function.identity/1)
defp parse_columns(string), do: String.split(string, "\n")
defp parse_row(row) do
row
|> String.split(" ")
|> Enum.map(&String.to_integer/1)
end
@doc """
Convert an `input` string, with rows separated by newlines and values
separated by single spaces, into a `Matrix` struct.
"""
@spec from_string(input :: String.t()) :: %Matrix{}
def from_string(input) do
matrix =
input
|> parse_columns()
|> Enum.map(&parse_row/1)
struct(__MODULE__, rows: matrix, columns: transpose(matrix))
end
@doc """
Write the `matrix` out as a string, with rows separated by newlines and
values separated by single spaces.
"""
@spec to_string(matrix :: %Matrix{}) :: String.t()
def to_string(matrix), do: Enum.map_join(matrix.rows, "\n", &Enum.join(&1, " "))
@doc """
Given a `matrix`, return its rows as a list of lists of integers.
"""
@spec rows(matrix :: %Matrix{}) :: list(list(integer))
def rows(matrix), do: matrix.rows
@doc """
Given a `matrix` and `index`, return the row at `index`.
"""
@spec row(matrix :: %Matrix{}, index :: integer) :: list(integer)
def row(matrix, index), do: at(matrix.rows, index)
@doc """
Given a `matrix`, return its columns as a list of lists of integers.
"""
@spec columns(matrix :: %Matrix{}) :: list(list(integer))
def columns(matrix), do: matrix.columns
@doc """
Given a `matrix` and `index`, return the column at `index`.
"""
@spec column(matrix :: %Matrix{}, index :: integer) :: list(integer)
def column(matrix, index), do: at(matrix.columns, index)
end