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