キーワードリストの利点は何ですか?


101

エリキシルにはマップがあります:

> map = %{:a => "one", :b => "two"} # = %{a: "one", b: "two"}
> map.a                             # = "one"
> map[:a]                           # = "one"

キーワードリストもあります。

> kl = [a: "one", b: "two"]       # = [a: "one", b: "two"]
> kl2 = [{:a, "one"},{:b, "two"}] # = [a: "one", b: "two"]
> kl == kl2                       # = true
> kl[:a]                          # = "one"
> kl.a                            # = ** (ArgumentError)

なぜ両方?

構文?キーワードリストにはより柔軟な構文があり、関数呼び出しの最後のパラメーターとして、中括弧や大括弧なしでも定義できるためですか?それでは、マップにこの構文糖を与えてみませんか?

重複するキー?キーワードリストに重複したキーが含まれる可能性があるためですか?マップスタイルのアクセスと重複キーの両方が必要なのはなぜですか?

パフォーマンス?キーワードリストの方がパフォーマンスが優れているためでしょうか。では、なぜマップがあるのですか?そして、マップはタプルのリストよりもキーでメンバーを検索する方がパフォーマンスが良くないのではないでしょうか?

JS配列とRubyハッシュのような外観ですか?それですか?

構造的には異なるデータ表現であることを理解しています。私には、elixirのキーワードリストは、例外的な構文(3つの異なる構文バリアント)、マップとの大文字と小文字の重複、および不明確な利点により、言語を複雑にするように見えます。

キーワードリストを使用する利点は何ですか?

回答:


143
                   ┌──────────────┬────────────┬───────────────────────┐
                   │ Keyword List │ Map/Struct │ HashDict (deprecated) │
┌──────────────────┼──────────────┼────────────┼───────────────────────┤
│ Duplicate keys   │ yes          │ no         │ no                    │
│ Ordered          │ yes          │ no         │ no                    │
│ Pattern matching │ yes          │ yes        │ no                    │
│ Performance¹     │ —            │ —          │ —                     │
│ ├ Insert         │ very fast²   │ fast³      │ fast⁴                 │
│ └ Access         │ slow⁵        │ fast³      │ fast⁴                 │
└──────────────────┴──────────────┴────────────┴───────────────────────┘

キーワードリストは軽量で、その下に単純な構造があるため、非常に柔軟です。これらは、Erlangの慣習の上にある構文糖と考えることができ、醜いコードを書かなくても、Erlangと簡単にやり取りできるようになります。たとえば、キーワードリストは、Erlangから継承されたプロパティである関数引数を表すために使用されます。場合によっては、特に重複するキーや順序が必要な場合は、キーワードリストが唯一の選択肢です。それらは単に他の選択肢とは異なるプロパティを持っているため、状況によってはより適切になり、他の状況には適さなくなります。

マップ(および構造体)は、ハッシュベースの実装があるため、実際のペイロードデータを格納するために使用されます。キーワードリストは内部的には、操作ごとに走査する必要があるリストにすぎないため、一定時間アクセスなどの従来のキー値データ構造のプロパティはありません。

エリクサーはまた、執筆時のマップのパフォーマンス低下HashDictに対する回避策として導入されました。ただし、これはElixir 1.0.5 / Erlang 18.0の時点で修正されており、将来のバージョンでは非推奨になる予定ですHashDict

Erlang標準ライブラリをさらに掘り下げると、キーと値のペアを格納するデータ構造がさらに多くなります。

  • proplists – Elixirキーワードリストに類似
  • マップ – Elixirマップと同じ
  • dict – Erlangプリミティブから構築されたキーと値の辞書
  • gb_trees –一般的なバランスツリー

複数のプロセスやVMにまたがってキーと値のペアを保存する必要がある場合にも、これらのオプションがあります。

  • ets / dets –(ディスクベース)Erlang用語ストレージ
  • mnesia –分散データベース

¹一般的に言えば、もちろん™ によって異なります。

²最良の場合は、リストの先頭に追加するだけです。

E Elixir 1.0.5以降に適用され、古いバージョンでは遅くなる場合があります。

HashDictは非推奨になりました。

average要素の半分を平均的にスキャンする線形検索が必要です。


1
重複するキーの許可と順序付けはメリットではなく、プロパティが異なります。ニーズに合ったデータ構造を選択する必要があります。
2015年

2
厳密に言えば、そうですが、これらのプロパティが必要な場合はメリットになる可能性があります。それが私の意図したことです。
Patrick Oscity、2015年

@PatrickOscity:そのような場合、確かにそれらは要件としてより適切に分類されますか?
オービットの軽量レース、2015年

11
@greggregキーワードリストを使用することには、もう1つの暗黙的な利点があります。構造化データと非構造化データを区別します。マップは、既知のキーのセットを持つ構造化データには非常に役立ちますが、キーワードはそうではありません。今日、マップの使用のほとんどは構造化データ用であり、オプションのキーワードにはキーワードを残しています。地図さえあれば、この区別の大部分は失われると思います。
ホセ・Valim

1
実際には、それは、マップはアーラン18から移動するための方法ですでした
Papipo

12

キーワードリストの主な利点は、既存のelixirおよびerlangコードベースとの下位互換性です。

ルビ構文などに似た関数の引数として使用すると、構文シュガーも追加されます。

def some_fun(arg, opts \\ []), do: ...
some_fun arg, opt1: 1, opt2: 2

キーワードリストを使用する主な欠点は、それらに対して部分的なパターンマッチングを実行できないことです。

iex(1)> m = %{a: 1, b: 2}
%{a: 1, b: 2}
iex(2)> %{a: a} = m
%{a: 1, b: 2}
iex(3)> a
1
iex(4)> k = [a: 1, b: 2]
[a: 1, b: 2]
iex(5)> [a: a] = k
** (MatchError) no match of right hand side value: [a: 1, b: 2]

関数の引数に拡張してみましょう。オプションの1つの値に基づいて複数句関数を処理する必要があると想像してください。

def fun1(arg, opt1: opt1) when is_nil(opt1), do: do_special_thing
def fun1(arg, opts), do: do_regular_thing

def fun2(arg, %{opt1: opt1}) when is_nil(opt1), do: do_special_thing
def fun2(arg, opts), do: do_regular_thing

これは決して実行しませんdo_special_thing

fun1("arg", opt1: nil, opt2: "some value")
doing regular thing  

マップ引数を使用すると機能します。

fun2("arg", %{opt1: nil, opt2: "some value"})
doing special thing

2

マップでは特定のキーに対して1つのエントリしか許可されませんが、キーワードリストではキーを繰り返すことができます。マップは効率がよく(特に成長するにつれて)、Elixirのパターンマッチングで使用できます。

一般に、コマンドラインパラメーターやオプションの受け渡しなどにキーワードリストを使用し、連想配列が必要な場合はマップ(または別のデータ構造、HashDict)を使用します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.