前回の記事に引き続き、99 Haskel Problems の問題を Elixir で解答します。
前回記事はこちらです。

なお、一部 Elixir の標準関数の仕様に合わせてアレンジしている問題があります。
Problem 11
Modified run-length encoding.
ランレングス符号化を改善せよ。
iex> Prob11.encode_modified("aaaabccaadeeee")
[{4, "a"}, "b", {2, "c"}, {2, "a"}, "d", {4, "e"}]解答例
defmodule Prob11 do
def encode_modified(string) do
string
|> String.graphemes()
|> Enum.chunk_by(&Function.identity/1)
|> Enum.map(&encode_inner/1)
end
def encode_inner(list) do
elem = List.first(list)
case length(list) do
1 -> elem
n -> {n, elem}
end
end
endProblem 12
Decode a run-length encoded list.
ランレングス符号を複合せよ。
iex> Prob12.decode_modified([{4, "a"}, "b", {2, "c"}, {2, "a"}, "d", {4, "e"}])
"aaaabccaadeeee"解答例
defmodule Prob12 do
def decode_modified(list) do
list |> Enum.map(&decode_inner/1) |> List.to_string()
end
defp decode_inner(elem) do
case elem do
{n, x} -> List.duplicate(x, n)
_ -> elem
end
end
endProblem 13
Run-length encoding of a list (direct solution).
直接的な手法でランレングス符号化を実装せよ。
(Problem 9 のようにサブリストを生成せずに実装する)
iex> Prob13.encode_direct("aaaabccaadeeee")
[{4, "a"}, "b", {2, "c"}, {2, "a"}, "d", {4, "e"}]解答例
defmodule Prob13 do
def encode_direct(string) do
string
|> String.graphemes()
|> List.foldr([], &encode_inner/2)
end
defp encode_inner(x, []), do: [x]
defp encode_inner(x, [head | tail]) do
case get_char(head) do
^x -> [count_up(head) | tail]
_ -> [x, head | tail]
end
end
defp get_char(elem) do
case elem do
{_, c} -> c
_ -> elem
end
end
defp count_up(elem) do
case elem do
{n, c} -> {n + 1, c}
c -> {2, c}
end
end
endProblem 14
Duplicate the element of a list.
リストの要素を複製せよ。
iex> Prob14.duplicate_each([1, 2, 3, 4])
[1, 1, 2, 2, 3, 3, 4, 4]解答例
defmodule Prob14 do
def duplicate_each(list), do: list |> List.foldr([], fn x, acc -> [x, x | acc] end)
endProblem 15
Replicate the elements of a list a given number of times.
リストの要素を指定された回数だけ繰り返せ。
iex> Prob15.replicate([1, 2, 3, 4], 3)
[1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]解答例
defmodule Prob15 do
def replicate(list, n), do: list |> Enum.map(&List.duplicate(&1, n)) |> Enum.concat()
endProblem 16
Drop every N’th element from a list.
リストの要素を N 番目ごとに削除せよ。
iex> Prob16.my_drop_every(1..10, 3)
[1, 2, 4, 5, 7, 8, 10]解答例
defmodule Prob16 do
def my_drop_every(enumerable, n) do
enumerable |> Enum.chunk_every(n) |> Enum.map(&Enum.take(&1, n - 1)) |> Enum.concat()
end
end標準ライブラリでの実行例
標準ライブラリには類似メソッドの Enum.drop_every があります。
この関数は、最初の要素から削除していく挙動を示し、問題とは異なる仕様です。
iex> Enum.drop_every(1..10, 3)
[2, 3, 5, 6, 8, 9]Problem 17
Split a list into two parts; the length of the first part is given.
リストを2つに分割せよ。引数には分割する要素数が与えられる。
iex> Prob17.my_split(1..10, 3)
{[1, 2, 3], [4, 5, 6, 7, 8, 9, 10]}解答例
defmodule Prob17 do
def my_split(enumerable, count) do
{Enum.take(enumerable, count), Enum.drop(enumerable, count)}
end
end標準ライブラリでの実行例
iex> Enum.split(1..10, 3)
{[1, 2, 3], [4, 5, 6, 7, 8, 9, 10]}Problem 18
Extract a slice from a list.
リストからスライスを抽出せよ。
iex> Prob18.my_slice(1..10, 3, 4)
[4, 5, 6, 7]解答例
defmodule Prob18 do
def my_slice(enumerable, start_index, amount) do
enumerable |> Enum.drop(start_index) |> Enum.take(amount)
end
end標準ライブラリでの実行例
iex> Enum.slice(1..10, 3, 4)
[4, 5, 6, 7]Problem 19
Rotate a list N places to the left.
リストを N要素だけ左にローテーションせよ。
iex> Prob19.rotate(1..10, 3)
[4, 5, 6, 7, 8, 9, 10, 1, 2, 3]
iex> Prob19.rotate(1..10, -2)
[9, 10, 1, 2, 3, 4, 5, 6, 7, 8]解答例
defmodule Prob19 do
def rotate(enumerable, n) do
cond do
n >= 0 -> Enum.drop(enumerable, n) ++ Enum.take(enumerable, n)
true -> Enum.take(enumerable, n) ++ Enum.drop(enumerable, n)
end
end
endProblem 20
Remove the K’th element from a list.
リストから K番目の要素を除去せよ。
iex> Prob20.my_delete_at([1, 2, 3, 4], 2)
[1, 2, 4]解答例
defmodule Prob20 do
def my_delete_at([], _), do: []
def my_delete_at([_ | tail], 0), do: tail
def my_delete_at([head | tail], n), do: [head | my_delete_at(tail, n - 1)]
end標準ライブラリでの実行例
iex> List.delete_at([1, 2, 3, 4], 2)
[1, 2, 4]



コメント