Recursion 10

Sieve - Exercism in Elixir

문제 보기 소수를 구하는 에라토스테네스의 체를 구현하는 문제였다. 개념은 쉬운데, 코드에서 나눗셈 또는 나머지 연산을 사용하지 말아야 한다는 조건이 붙었다(대신 곱셈을 사용하라는 의도). 우선 처음에 나눗셈을 사용해서 짠 간단한 코드는 이쪽. defmodule Sieve do @doc """ Generates a list of primes up to a given limit. """ @spec primes_to(non_neg_integer) :: [non_neg_integer] def primes_to(limit) do 2..limit//1 |> Enum.to_list() |> do_primes_to([]) |> Enum.reverse() end defp do_primes_to([], primes), d..

Spiral Matrix - Exercism in Elixir

문제 보기 1부터 n^2까지의 자연수를 n*n의 행렬에 왼쪽 위부터 시계방향으로 시작하여 소용돌이 모양으로 배치하는 문제였다. 예를 들면 이런 식이다. iex> matrix(4) [ [ 1, 2, 3, 4], [12, 13, 14, 5], [11, 16, 15, 6], [10, 9, 8, 7] ] 이걸 어떻게 해야 하나 싶어 고민하느라 시간을 제법 썼는데, n=2까지의 행렬에 대해서는 숫자가 들어갈 위치를 하드코딩으로 정해 두고, n >= 3부터는 (n-2)*(n-2) 행렬의 외부에 숫자를 한 바퀴 두르면 된다는 것을 깨닫고 그렇게 구현했다. 이 부분을 spiral/1 함수로 구현하여 숫자가 들어갈 좌표를 순서대로 반환하도록 하고, 여기에 Enum.with_index/1로 숫자를 붙인 뒤에 출력 형식에 ..

Pascals Triangle - Exercism in Elixir

문제 보기 파스칼 삼각형(https://ko.wikipedia.org/wiki/%ED%8C%8C%EC%8A%A4%EC%B9%BC%EC%9D%98_%EC%82%BC%EA%B0%81%ED%98%95)을 구현하는 문제였다. 조합(combination)으로 삼각형을 정의하면 줄 번호만 알아도 독립적으로 행을 계산할 수 있어 그렇게 할까 했는데 계산이 귀찮아서, 그냥 직전 리스트를 chunk_every 한 뒤 합치는 식으로 구현했다. 분명 easy 난이도 문제였는데 생각보다 시간을 많이 썼다. 일단 처음에 Enum.reduce를 사용해 구현한 버전은 이것. defmodule PascalsTriangle do @doc """ Calculates the rows of a pascal triangle with the ..

Killer Sudoku Helper - Exercism in Elixir

문제 보기 스도쿠의 룰에 더해, 연속된 몇몇 칸의 숫자 합이 추가 힌트로 주어지는 '킬러 스도쿠'라는 것이 있다. 세 칸의 합이 6이면 어떤 숫자가 어떤 칸에 들어가는지는 모르더라도 그 칸에는 1, 2, 3이 들어가겠구나 하고 유추할 수 있는 것이다. 이번 문제는 킬러 스도쿠를 푸는 도우미 함수를 작성하는 문제였다. 제외해야 할 숫자, 칸의 크기, 합을 입력하면 가능한 경우들을 반환해야 했다. 칸의 수가 유동적이라 리스트 컴프리헨션을 사용할 수도 없고 고민했는데, 결국 어찌어찌 재귀를 이용해 풀었다. defmodule KillerSudokuHelper do @doc """ Return the possible combinations of `size` distinct numbers from 1..

Matching Brackets - Exercism in Elixir

문제 보기 재귀 처리를 익히는 기본 문제 중 하나인 괄호 짝 맞추기 문제다. 다 풀고 나서 생각해보니 String.graphemes로 문자열을 리스트로 만들고 리스트 패턴 매칭을 하는 게 코드상으로는 조금 더 간단했을 것 같은데, 왜인지 바이너리 패턴 매칭을 써야겠다 싶었다. 연습도 되고 좋았다. defmodule MatchingBrackets do @doc """ Checks that all the brackets and braces in the string are matched correctly, and nested correctly """ @spec check_brackets(String.t()) :: boolean def check_brackets(str) do do_check(str, []) e..

Binary Search Tree - Exercism in Elixir

문제 보기 이진 검색 트리를 구현하는 문제였다. 구현하는 것 자체는 어렵지 않았는데, 이렇게 꼬리 재귀 최적화의 도움을 못 받는 코드를 엘릭서에서 작성해도 과연 괜찮은 것인가 하는 의문이 남는다. defmodule BinarySearchTree do @type bst_node :: %{data: any, left: bst_node | nil, right: bst_node | nil} @doc """ Create a new Binary Search Tree with root's value as the given 'data' """ @spec new(any) :: bst_node def new(data) do %{data: data, left: nil, right: nil} end @d..

Binary Search - Exercism in Elixir

문제 보기 이진 검색을 구현하는 문제였다. 함수형 언어를 익히는 과정에서 map, reduce를 직접 구현해보는 것과 마찬가지로 기초적인 알고리즘을 익히는 것이 포인트가 되는 문제일 것이다. 사실 리스트에 인덱스로 직접 접근하는 일이 엘릭서에서는 거의 없어서 의미가 있을까... 싶긴 한데, 그걸 의식한 듯 문제가 튜플로 주어진 것이 인상적이었다. 테마를 보니 cond를 쓰는 문제였던 것 같은데, 이 구현의 경우에는 계산은 한 번만 하고 그걸 case로 가져다쓰는 쪽이 나을 것 같아서 그렇게 구현했다. defmodule BinarySearch do @doc """ Searches for a key in the tuple using the binary search algorithm. It returns :n..

Roman Numerals - Exercism in Elixir

문제 보기 10진수 숫자를 로마자로 변환하는 문제였다. 구현에 고민을 제법 한 문제였다. 재귀를 쓸 수도 있고 그 외에도 여러 가지 방법을 쓸 수 있었을 것 같다(다 풀고 발견한 것이었지만 이 문제는 재귀를 연습하기 위해 만들어진 듯하다). 이번에 Exercism을 풀면서는 전체적으로 매핑의 가짓수가 늘어나더라도(예를 들어 지금은 천 단위 숫자까지만 변환하면 됐지만 이후 대응해야 하는 수의 크기가 커지는 경우를 생각) 코드 수정 없이 데이터만 수정하면 되도록 해보고 싶어서 데이터 부분을 별도 맵으로 분리해서 코드를 짜 보았다. defmodule RomanNumerals do @exp_to_roman_mapping %{ 0 => %{1 => "I", 4 => "IV", 5 => "V", 9 => "IX"}..

Strain - Exercism in Elixir

문제 보기 명제(predicate)가 참일 때, 또는 거짓일 때 리스트의 항목을 필터링하는 keep과 discard 함수를 구현하는 문제였다. ...다시 말해 Enum.filter, reject 두 함수를 구현하는 문제였다. 기본 제공되는 기능들을 직접 구현하는 과제는 여러 번 해본 터라, 이번에도 큰 어려움이 없었다. defmodule Strain do @doc """ Given a `list` of items and a function `fun`, return the list of items where `fun` returns true. Do not use `Enum.filter`. """ @spec keep(list :: list(any), fun :: (any -> boolean)) :: list..

Bird Count - Exercism in Elixir

문제 보기 재귀를 사용해 count, sum 등의 동작을 직접 구현해야 하는 문제였다. 가끔 이렇게 야크 털을 직접 깎는 것도 또 재미다. defmodule BirdCount do def today([]), do: nil def today([h | _t]), do: h def increment_day_count([]), do: [1] def increment_day_count([h | t]), do: [h + 1 | t] def has_day_without_birds?([]), do: false def has_day_without_birds?([h | _t]) when h == 0, do: true def has_day_without_birds?([_h | t]), do: has_day_without_b..