Lists 10

List Ops - Exercism in Elixir

문제 보기 엘릭서에서 제공되는 내장 함수들(Kernel의 리스트 연산 함수들, List, Enum 등)을 쓰지 않고 리스트 연산을 구현해보는 문제였다. 리스트 연산을 공부하는 사람들이라면 한번쯤은 짜 봤을 법한 기본적인 내용. 하나하나 구현하다가, 생각해보니 엘릭서의 Enum이 그렇듯 대부분의 것을 reduce(=foldl)로 처리할 수 있음을 깨닫고 그렇게 고쳤다. 기록이 될까 싶어 고치기 전후 버전을 코드에 모두 남겨둔다. do_reverse, do_map 등 호출되지 않는 함수들이 고치기 전의 코드다. defmodule ListOps do # Please don't use any external modules (especially List or Enum) in your # implementa..

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..

Scale Generator - Exercism in Elixir

문제 보기 음계 계산과 관련된 여러 함수를 구현하는 문제였다. 특정 음에서 1도~3도 떨어진 음은 무엇인가, 특정 음에서 시작하는 1옥타브를 플랫 또는 샵 표현으로 나타내거나 등등. 마지막 함수는 앞에서 구현한 함수들을 모두 활용해야 하는 문제였어서 과제가 유기적으로 연결된 듯 하여 재미있게 풀었다. defmodule ScaleGenerator do @spec step(scale :: list(String.t()), tonic :: String.t(), step :: String.t()) :: String.t() def step(scale, tonic, step) do tonic_index = scale |> Enum.find_index(fn s -> s == tonic end) index = case ..

Saddle Points - Exercism in Elixir

문제 보기 행렬의 같은 행 중에서 가장 값이 크고, 같은 열 중에서 가장 값이 작은 지점을 안장점(Saddle point)이라고 한다고 한다. 문자열로 행렬이 주어졌을 때 안장점을 찾는 문제였다. 코드에 중복이 많아서 조금 길기는 한데, 애초에 문제가 상당 부분 Matrix와 중복이기도 해서 크게 신경쓰지 않고 풀었다. defmodule SaddlePoints do @doc """ Parses a string representation of a matrix to a list of rows """ @spec rows(String.t()) :: [[integer]] def rows(str) do str |> String.split("\n", trim: true) |> Enum.map(fn r -> r |> ..

Matrix - Exercism in Elixir

문제 보기 문자열로 행렬의 내용이 주어졌을 때 이를 자료구조로 변환하고, 특정 행 또는 열의 값을 조회하는 문제였다. 문제 분야가 Tuple로 적혀 있는 걸 보니 튜플을 사용하는 것을 의도한 모양인데, 입력 형식도 출력 형식도 리스트인데 굳이 튜플을 쓸 이유가 없다. defmodule Matrix do defstruct matrix: nil @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(inp..

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로 숫자를 붙인 뒤에 출력 형식에 ..

Flatten Array - Exercism in Elixir

문제 보기 중첩 리스트를 평탄회(flatten)하되, nil을 제거하는 문제였다. 비슷한 코드를 Advent of code 2021 하면서 작성해본 적이 있어서 그런지, 손 가는 대로 했더니 한번에 통과해버렸다(헤헤). 다만 성능에는 별 자신이 없다. defmodule FlattenArray do @spec flatten(list) :: list def flatten(list) do Enum.reduce(list, [], fn nil, acc -> acc sublist, acc when is_list(sublist) -> acc ++ flatten(sublist) v, acc -> acc ++ [v] end) end end

Sublist - Exercism in Elixir

문제 보기 리스트 두 개가 주어졌을 때 서로 포함 관계인지를 확인하는 문제였다. Easy 난이도 문제였음에도 제법 까다로웠다. 테스트 케이스에 100만 단위 리스트가 있어서, 퍼포먼스를 챙기려면 항목을 하나하나 비교하다가 틀린 것이 확실해지자마자 빠져나와야겠다 싶어 처음에는 재귀로 작성했었다. 그런데 하다 보니 영 아닌 것 같아 다른 사람들의 답을 확인해봤더니 List.starts_with?를 쓰고 있기에 '이렇게 쉽게 짜도 된다고?' 하면서 어리벙벙하며 가져와 완성한 것이 지금 코드. 지금까지의 문제와 달리 웹상에서는 실행되지 않는 무거운 테스트들이 있는데, 거기까지 테스트해보지는 않았다. 부디 잘 돌아갔으면 한다. defmodule Sublist do @doc """ Returns wh..

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..

Language List - Exercism in Elixir

문제 보기 기본적인 리스트 연산을 수행하는 문제였다. 역시 직관적인 문제가 이해하기에는 편하다. 엘릭서 리스트가 내부적으로 연결 리스트(linked list)라는 사실과 패턴 매칭을 이용하면 깔끔한 코드를 작성할 수 있다. defmodule LanguageList do def new() do [] end def add(list, language) do [language | list] end def remove([_hd | tl]) do tl end def first([hd | _tl]) do hd end def count(list) do length(list) end def exciting_list?(list) do "Elixir" in list end end count 함수에는 처음에 Enum.coun..