В чем преимущество списков ключевых слов?

В эликсире мы имеем Карты:

> 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 Array и Ruby Hash, как внешний вид? Это что?

Я понимаю, что структурно они представляют собой разные представления данных. Мне кажется, что списки ключевых слов в эликсире служат для усложнения языка с помощью исключительного синтаксиса (3 разных синтаксических варианта), перекрытие с использованием примеров с картами и неявное преимущество.

В чем преимущество использования списков ключевых слов?

Ответ 1

                   ┌──────────────┬────────────┬───────────────────────┐
                   │ 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
  • maps - то же, что и карты Elixir
  • dict - словари с ключом, созданные из примитивов Erlang.
  • gb_trees - общее сбалансированное дерево

У вас также есть эти параметры, когда вам нужно хранить пары ключ/значение для нескольких процессов и/или виртуальных машин:

  • ets/dets - ( на основе диска) Эрлангский термин хранения
  • mnesia - распределенная база данных

¹ Вообще говоря, но, конечно, это зависит от.

² Лучший случай просто добавляет к списку.

³ Применимо к Elixir 1.0.5 и выше, может быть медленнее в более старых версиях.

HashDict теперь устарел.

⁵ Требуется линейный поиск, который в среднем сканирует половину элементов.

Ответ 2

Основное преимущество списков ключевых слов - это обратная совместимость с существующей кодовой базой elixir и erlang.

Они также добавляют синтаксический сахар, если они используются в качестве аргументов функций, которые напоминают, например, синтаксис ruby:

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]

Допустим его до аргументов функции. Представьте себе, что нам нужно обрабатывать функцию многозадачности, основанную на значении одного из параметров:

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

Ответ 3

Карты допускают только одну запись для определенного ключа, тогда как списки ключевых слов позволяют повторять ключ. Карты эффективны (особенно по мере их роста), и они могут быть используется в сопоставлении с образцами Elixirs.

В общем, используйте списки ключевых слов для таких вещей, как параметры командной строки и для передачи параметров, а также использовать карты (или другую структуру данных, HashDict), когда вам нужен ассоциативный массив.