Elixir | 99-Haskell Problems 問題 11 – 20 解答例

前回の記事に引き続き、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
end

Problem 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
end

Problem 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
end

Problem 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)
end

Problem 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()
end

Problem 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
end

Problem 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]
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次