Список — это встроенный тип данных коллекции в elixir, который может содержать упорядоченные разнородные элементы. Списки в elixir построены на основе одноименного типа данных List системы типов erlang. Списки в эликсире внутренне ведут себя как отдельные связанные списки.

Синтаксис

Списки могут быть определены с использованием синтаксиса квадратных скобок [], содержащего элементы в виде значений, разделенных запятыми, в квадратных скобках.

a = [] #empty list
b = [1, 2.0, :atom_1, "ello", [2,3,4]] #list containing five elements

Поскольку списки в эликсире являются внутренне связанными списками, каждый список можно представить в виде пары «голова» и «хвост». Голова — это первый элемент списка, а хвост — это список, содержащий остальные элементы. Этот шаблон продолжается рекурсивно до конца списка, где последний элемент неявно является пустым списком. Синтаксис представления головы и хвоста списка использует оператор cons | для разделения головы и хвоста списка. Возьмем список, содержащий 5 элементов [1, 2, 3, 4, 5]. В этом списке элемент 1 является головой, а хвост — списком, содержащим остальные элементы. Таким образом, этот список также можно записать в соответствии с обозначениями головы и хвоста как [1 | [2, 3, 4, 5]]. Хвост списка, также являющийся еще одним списком, может быть дополнительно записан как обозначение начала и хвоста. Эта нотация выразительна и полезна при рекурсии, сопоставлении с образцом и добавлении элементов в список. Обратите внимание: если при использовании записи головы и хвоста последний элемент в списке не обозначен как список, результатом будет неправильный список.

[1,2,3,4,5]
[1|[2,3,4,5]]
[1|[2|[3,4,5]]]
[1|[2|[3|[4,5]]]]
[1|[2|[3|[4|[5]]]]]
[1|[2|[3|[4|[5|[]]]]]]

[1|[2|[3]] #valid list [1,2,3] 
[1|[2|3]] #improper list [1,2|3]

Добавление и добавление

Добавлять элементы в конец списков можно с помощью оператора конкатенации списков ++, предусмотренного в модуле Ядро. Второй операнд должен представлять собой список, содержащий добавляемые элементы. Использование оператора ++ для одного элемента без заключения его в квадратные скобки снова приведет к неправильному списку. Подобно оператору конкатенации списков, существует также оператор вычитания списка — — , который удаляет первое вхождение всех элементов второго операнда из первого операнда.

[1,2,3] ++ [4,5] #[1,2,3,4,5]
[1,2,3,4] ++ [5] #[1,2,3,4,5]
[1,2,3,4] ++ 5 #improper list [1,2,3,4|5]

[1,2,3,1,2] -- [1,2,4] #[3,1,2]

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

a = [2,3,4]
[1 | a] #[1,2,3,4]
[-1,0,1 | a] #[-1,0,1,2,3,4]

Справочные модули

Модуль ядра имеет такие функции, как hd/1, который возвращает начало списка, tl/1, который возвращает хвост списка, length/1, который возвращает длину списка, и такие операторы, как in/2, которые возвращают true, если элемент присутствует в списке. Модуль Список предоставляет множество функций, которые работают и манипулируют типом данных списка. Обратите внимание, что все типы данных в эликсире неизменяемы, и, следовательно, все функции, работающие со списками, возвращают новый список и никогда не изменяют исходный список. Поскольку тип данных List реализует протокол Enumerable, со списками могут работать модули Enum и Stream, содержащие множество полезных функций.

hd([1,2,3]) # 1
tl([1,2,3]) # [2,3]
length([1,2,3]) # 3
1 in [1,2,3] # true
5 in [1,2,3] # false

Enum.at([1,2,3],0) # returns first element of the list - O(n)

Списки символов

Обратите внимание, что если списки содержат целые числа, которые являются допустимыми символами ASCII, то список печатается как список символов. Фактически, список символов — это просто список целых чисел, обозначающих печатные символы. Список символов может быть определен напрямую с использованием синтаксиса 'content', и он является частью elixir для обеспечения обратной совместимости с erlang. Строковое представление по умолчанию в erlang — это список символов, а в elixir строка представлена ​​в виде двоичных файлов. Следовательно, представление двоичной строки в эликсире должно быть преобразовано в список символов перед использованием функции erlang, которая принимает строку в качестве аргумента, и наоборот.

IO.puts([97, 98, 99]) # prints the equivalent ascii characters - abc 
IO.puts([97,98,1000]) # prints [97,98,1000] as 1000 is not a valid ascii char
'hello' ==  [104, 101, 108, 108, 111] # true
'😘🖤💖' # internal list representation [128536, 128420, 128150]

Если вас интересует внутреннее представление данных списков, прочтите эту статью.