2
\$\begingroup\$

As I'm learning elixir, I wrote some code for printing elements in the spiral of a matrix(2D array). I was wondering if there is any room for improvements with regards to its performance or refactoring of any kind.

defmodule MatrixSpiralPrint do
  @moduledoc """
    Solution to Spiral print of elements of a matrix(2D array)
  """

  @doc """
  prints elements of matrix(2D array) in a spiral

  ## Examples

      iex> matrix = [[1,   2,  3, 4], [12, 13, 14, 5], [11, 16, 15, 6], [10,  9,  8, 7]]
      iex> MatrixSpiralPrint.spriral_print_matrix(matrix)
      [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

  """
  def spriral_print_matrix(matrix) do
    case List.improper?(matrix) do
      true -> "Not a valid matrix"
      false -> has_rows(matrix)
    end
  end

  def has_rows(matrix) do
    row = Enum.at(matrix, 0)
    case List.improper?(row) do
      true -> "Does not contain a row"
      false -> spiral_print(matrix)
    end
  end

  def spiral_print(matrix) do
    row_min = 0
    row_max = length(matrix) - 1
    column_min = 0
    column_max = length(Enum.at(matrix, 0, 0)) - 1

    matrix
    |> spiral_print(row_min, row_max, column_min, column_max)
  end

  def spiral_print(matrix, row_min, row_max, column_min, column_max) do
    print_matrix(row_min < row_max and column_min < column_max, matrix, row_min, row_max, column_min, column_max)
  end

  def print_matrix(true, matrix, row_min, row_max, column_min, column_max) do
    # IO.puts(:stdio, "row_min: #{row_min}, row_max: #{row_max} column_min: #{column_min}, column_max: #{column_max}")
    print_left_to_right(column_min <= column_max, matrix, row_min, column_min, column_max)
    row_min = row_min + 1

    # IO.puts(:stdio, "row_min: #{row_min}, row_max: #{row_max} column_min: #{column_min}, column_max: #{column_max}")
    print_top_to_bottom(row_min <= row_max, matrix, row_min, column_max, row_max)
    column_max = column_max - 1

    # IO.puts(:stdio, "row_min: #{row_min}, row_max: #{row_max} column_min: #{column_min}, column_max: #{column_max}")
    print_right_to_left(column_min <= column_max, matrix, row_max, column_max, column_min)
    row_max = row_max - 1

    # IO.puts(:stdio, "row_min: #{row_min}, row_max: #{row_max} column_min: #{column_min}, column_max: #{column_max}")
    print_bottom_to_top(row_min <= row_max, matrix, row_max, column_min, row_min)
    column_min = column_min + 1

    # IO.puts(:stdio, "==============================================================")
    # IO.puts(:stdio, "row_min: #{row_min}, row_max: #{row_max} column_min: #{column_min}, column_max: #{column_max}")
    print_matrix(row_min < row_max and column_min < column_max, matrix, row_min, row_max, column_min, column_max)
  end

  def print_matrix(false, _matrix, _row_min, _row_max, _column_min, _column_max) do
    :ok # IO.puts(:stdio, "End of the matrix")
  end

  def print_left_to_right(true, matrix, row, column, limit) do
    # IO.puts(:stdio, "row: #{row}, column: #{column}, limit: #{limit}")
    IO.puts(:stdio, Enum.at(Enum.at(matrix, row), column))
    print_left_to_right(column < limit, matrix, row, column+1, limit)
  end

  def print_left_to_right(false, _matrix, _row, _column, _limit) do
    :ok # do nothing
  end

  def print_top_to_bottom(true, matrix, row, column, limit) do
    # IO.puts(:stdio, "row: #{row}, column: #{column}, limit: #{limit}")
    IO.puts(:stdio, Enum.at(Enum.at(matrix, row), column))
    print_top_to_bottom(row < limit, matrix, row+1, column, limit)
  end

  def print_top_to_bottom(false, _matrix, _row, _column, _limit) do
    :ok # do nothing
  end

  def print_right_to_left(true, matrix, row, column, limit) do
    # IO.puts(:stdio, "row: #{row}, column: #{column}, limit: #{limit}")
    IO.puts(:stdio, Enum.at(Enum.at(matrix, row), column))
    print_right_to_left(limit < column, matrix, row, column-1, limit)
  end

  def print_right_to_left(false, _matrix, _row, _column, _limit) do
    :ok # do nothing
  end

  def print_bottom_to_top(true, matrix, row, column, limit) do
    # IO.puts(:stdio, "row: #{row}, column: #{column}, limit: #{limit}")
    IO.puts(:stdio, Enum.at(Enum.at(matrix, row), column))
    print_bottom_to_top(limit < row, matrix, row-1, column, limit)
  end

  def print_bottom_to_top(false, _matrix, _row, _column, _limit) do
    :ok # do nothing
  end
end

Code is also available for review on gist. Link to the gist.

Edit:

Updated code by removing if conditions in favor of pattern matching. Please let me know if there's something that I can learn to improve the coding. For example, I was wondering if there could be a neater way to get rid-off of the long arguments list for each print function.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.