9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Elixirでいろいろな長さをはかる

Last updated at Posted at 2020-01-05

はじめに

  • Elixirでいろいろな長さをはかってみたいとおもいます
  • きっかけはMapの長さってどうやって調べるのだっけ? とおもったことがきっかけです
    • 長さが欲しくなることは実はあんまりなかったりする気もしていますが、いろいろ試してみたこと書いておきます

この記事でのElixirのバージョン

% iex
Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Interactive Elixir (1.9.4) - press Ctrl+C to exit (type h() ENTER for help)

まとめ

List

iex> [1, 2, 3] |> length
3
iex> [1, [2, 3], 4, 5] |> Enum.count
4

Keyword

iex> [exit_on_close: true, active: :once, packet_size: 1024] |> length
3
iex> [exit_on_close: true, active: :once, packet_size: 1024] |> Enum.count
3

Map

iex> %{hoge: 1, fuga: 2} |> map_size
2
iex> %{hoge: 1, fuga: 2, foo: %{hoge: 1, fuga: 2}} |> Enum.count
3
iex> %{hoge: 1, fuga: 2, foo: %{hoge: 1, fuga: 2}} |> length
** (ArgumentError) argument error
    :erlang.length(%{foo: %{fuga: 2, hoge: 1}, fuga: 2, hoge: 1})

Range

iex> 1..3 |> Enum.count
3
iex> 1..3 |> length
** (ArgumentError) argument error
    :erlang.length(1..3)

文字列

iex> "あいう" |> String.length
3
iex> "あいう" |> byte_size    
9
iex> "あいう" |> length
** (ArgumentError) argument error
    :erlang.length("あいう")
iex> "あいう" |> Enum.count
** (Protocol.UndefinedError) protocol Enumerable not implemented for "あいう" of type BitString
    (elixir) lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir) lib/enum.ex:153: Enumerable.count/1
    (elixir) lib/enum.ex:600: Enum.count/1

文字リスト

iex> '123' |> length
3
iex> '123' |> Enum.count
3

MapSet

iex> map_set = MapSet.new([1,2,2,3,4,5,3])
# MapSet<[1, 2, 3, 4, 5]>
iex> map_set |> MapSet.size
5
iex> map_set |> Enum.count 
5
iex> map_set |> length
** (ArgumentError) argument error
    :erlang.length(#MapSet<[1, 2, 3, 4, 5]>)

Tuple

iex> {1, :two, "three"} |> tuple_size
3
iex> {1, :two, "three"} |> length
** (ArgumentError) argument error
    :erlang.length({1, :two, "three"})
iex> {1, :two, "three"} |> Enum.count
** (Protocol.UndefinedError) protocol Enumerable not implemented for {1, :two, "three"} of type Tuple
    (elixir) lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir) lib/enum.ex:153: Enumerable.count/1
    (elixir) lib/enum.ex:600: Enum.count/1

Stream

iex> Stream.iterate(0, &(&1 + 1)) |> Enum.count
  • 結果は得られません

バイナリ

iex> <<1,2,3>> |> byte_size
3
iex> <<1,2,3>> |> bit_size
24
iex> <<1,2,3>> |> length
** (ArgumentError) argument error
    :erlang.length(<<1, 2, 3>>)
iex> <<1,2,3>> |> Enum.count
** (Protocol.UndefinedError) protocol Enumerable not implemented for <<1, 2, 3>> of type BitString
    (elixir) lib/enum.ex:1: Enumerable.impl_for!/1
    (elixir) lib/enum.ex:153: Enumerable.count/1
    (elixir) lib/enum.ex:600: Enum.count/1

lengthとsizeのElixirにおける意味について

  • gumi TECH BlogElixir入門 16: プロトコル を読んで知りました
    • ありがとうございます!
  • 公式にもかいてあります!
  • lengthは全部数え上げるから要素の数に比例して処理時間がかかる、sizeはデータ構造にサイズをもっているので一定時間で長さを返せる そうです(正確な意味は上記の原文をお読みください)

Enum.count/1はどうなのでしょうか

  @doc """
  Returns the size of the `enumerable`.

  ## Examples

      iex> Enum.count([1, 2, 3])
      3

  """
  @spec count(t) :: non_neg_integer
  def count(enumerable) when is_list(enumerable) do
    length(enumerable)
  end

  def count(enumerable) do
    case Enumerable.count(enumerable) do
      {:ok, value} when is_integer(value) ->
        value

      {:error, module} ->
        enumerable |> module.reduce({:cont, 0}, fn _, acc -> {:cont, acc + 1} end) |> elem(1)
    end
  end
  • Listだったら、Kernel.length/1 呼ぶ
  • Enumerable.count/1で、{:ok, 整数}だったら、その整数を返す
  • Enumerable.count/1で、{:error, module}だったら、module.reduce/3 で数え上げる
  • ということをやっているようです
iex(3)> is_list([1,2,3])
true # Enum.count([1,2,3])はこの結果によって、length([1,2,3])を呼び出して数え上げる
iex> Enumerable.count(%{hoge: 1, fuga: 2})
{:ok, 2} # Enum.count(%{hoge: 1, fuga: 2})はこの結果により、2を返す
iex> Enumerable.count(1..3)
{:ok, 3} # Enum.count(1..3)はこの結果により、3を返す
iex> '123' |> Enumerable.count
{:error, Enumerable.List} # Enum.count('123')はこの結果によってEnumerable.List.reduce/3で数え上げる
  • データ型に応じて賢く長さを取得しているようです!
9
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?