Диапазон
Диапазоны представляют собой последовательность нуля, одного или многих возрастающих или убывающих целых чисел с общей разностью, называемой шагом.
Наиболее распространённый способ создания и сопоставления с диапазонами — использование обозначений first..last и first..last//step, автоматически импортируемых из Kernel:
iex> 1 in 1..10 true iex> 5 in 1..10 true iex> 10 in 1..10 true
Диапазоны всегда включают крайние значения в Elixir. Когда задан шаг, целые числа будут принадлежать диапазону только в том случае, если они соответствуют шагу:
iex> 5 in 1..10//2 true iex> 4 in 1..10//2 false
При определении диапазона без шага шаг будет определён на основе первого и последнего значения диапазона. Если last >= first, это будет возрастающий диапазон с шагом 1. В противном случае, это убывающий диапазон. Однако следует отметить, что неявные убывающие диапазоны устарели. Поэтому, если вам нужен убывающий диапазон от 3 до 1, предпочтительнее написать 3..1//-1 вместо этого.
../0 также может использоваться как сокращение для создания диапазона 0..-1//1, также известного как диапазон полного среза:
iex> .. 0..-1//1
Сценарии использования
Диапазоны обычно используются в Elixir для двух целей: как коллекция или для представления среза другой структуры данных.
Диапазоны как коллекции
Диапазоны в Elixir являются перечисляемыми и поэтому могут использоваться с модулем Enum:
iex> Enum.to_list(1..3) [1, 2, 3] iex> Enum.to_list(3..1//-1) [3, 2, 1] iex> Enum.to_list(1..5//2) [1, 3, 5]
Диапазоны также могут содержать единственный элемент:
iex> Enum.to_list(1..1) [1] iex> Enum.to_list(1..1//2) [1]
Или даже не содержать элементов:
iex> Enum.to_list(10..0//1) [] iex> Enum.to_list(0..10//-1) []
Диапазон полного среза, возвращаемый ../0, является пустой коллекцией:
iex> Enum.to_list(..) []
Диапазоны как срезы
Диапазоны также часто используются для выделения срезов коллекций. Вы можете выделить срез строк или любого перечисляемого объекта:
iex> String.slice("elixir", 1..4)
"lixi"
iex> Enum.slice([0, 1, 2, 3, 4, 5], 1..4)
[1, 2, 3, 4]
В этих случаях первые и последние значения диапазона отображаются на позиции в коллекциях.
Если задано отрицательное число, оно отображается на позицию с конца:
iex> String.slice("elixir", 1..-2//1)
"lixi"
iex> Enum.slice([0, 1, 2, 3, 4, 5], 1..-2//1)
[1, 2, 3, 4]
Диапазон 0..-1//1, возвращаемый ../0, возвращает коллекцию как есть, поэтому он называется диапазоном полного среза:
iex> String.slice("elixir", ..)
"elixir"
iex> Enum.slice([0, 1, 2, 3, 4, 5], ..)
[0, 1, 2, 3, 4, 5]
Определение
Возрастающий диапазон first..last//step — это диапазон от first до last с возрастанием на step, где step должно быть положительным целым числом, а все значения v должны быть first <= v and v <= last. Таким образом, диапазон 10..0//1 является пустым диапазоном, так как нет значения v, которое является 10 <= v and v <= 0.
Аналогично, убывающий диапазон first..last//step — это диапазон от first до last с убыванием на step, где step должно быть отрицательным целым числом, а значения v должны быть first >= v and v >= last. Таким образом, диапазон 0..10//-1 является пустым диапазоном, так как нет значения v, которое является 0 >= v and v >= 10.
Представление
Внутри диапазоны представлены в виде структур:
iex> range = 1..9//2 1..9//2 iex> first..last//step = range iex> first 1 iex> last 9 iex> step 2 iex> range.step 2
Вы можете напрямую получить доступ к полям диапазона (first, last, и step), но не должны изменять или создавать диапазоны вручную. Вместо этого используйте соответствующие операторы или new/2 и new/3.
Диапазоны реализуют протокол Enumerable с эффективными по памяти версиями всех вызовов обратного вызова Enumerable:
iex> range = 1..10 1..10 iex> Enum.reduce(range, 0, fn i, acc -> i * i + acc end) 385 iex> Enum.count(range) 10 iex> Enum.member?(range, 11) false iex> Enum.member?(range, 8) true
Такие вызовы функций эффективны с точки зрения памяти, независимо от размера диапазона. Реализация протокола Enumerable использует логику, основанную только на конечных точках, и не материализует весь список целых чисел.
Краткое описание
Типы
Функции
- disjoint?(range1, range2)
Проверяет, являются ли два диапазона непересекающимися.
- new(first, last)
Создаёт новый диапазон.
- new(first, last, step)
Создаёт новый диапазон с
step.- shift(arg, steps_to_shift)
Смещает диапазон на указанное количество шагов.
- size(range)
Возвращает размер
range.
Типы
Функции
disjoint?(range1, range2)Source
@spec disjoint?(t(), t()) :: boolean()
Проверяет, являются ли два диапазона непересекающимися.
Примеры
iex> Range.disjoint?(1..5, 6..9) true iex> Range.disjoint?(5..1, 6..9) true iex> Range.disjoint?(1..5, 5..9) false iex> Range.disjoint?(1..5, 2..7) false
Шаги также учитываются при вычислении непересекающихся диапазонов:
iex> Range.disjoint?(1..10//2, 2..10//2) true # First element in common in all below is 29 iex> Range.disjoint?(2..100//3, 9..100//5) false iex> Range.disjoint?(101..2//-3, 99..9//-5) false iex> Range.disjoint?(1..100//14, 8..100//21) false iex> Range.disjoint?(57..-1//-14, 8..100//21) false iex> Range.disjoint?(1..100//14, 51..8//-21) false # If 29 is out of range iex> Range.disjoint?(1..28//14, 8..28//21) true iex> Range.disjoint?(2..28//3, 9..28//5) true
new(first, last)Source
@spec new(limit(), limit()) :: t()
Создаёт новый диапазон.
Если first меньше last, диапазон будет возрастающим от first до last. Если first равно last, диапазон будет содержать один элемент — это число само по себе.
Если first больше last, диапазон будет убывающим от first до last, хотя такое поведение устарело. Поэтому рекомендуется явно указать шаг с помощью new/3.
Примеры
iex> Range.new(-100, 100) -100..100
new(first, last, step)Source
@spec new(limit(), limit(), step()) :: t()
Создаёт новый диапазон с step.
Примеры
iex> Range.new(-100, 100, 2) -100..100//2
shift(arg, steps_to_shift)Source
Сдвигает диапазон на заданное количество шагов.
Примеры
iex> Range.shift(0..10, 1) 1..11 iex> Range.shift(0..10, 2) 2..12 iex> Range.shift(0..10//2, 2) 4..14//2
size(range)Source
Возвращает размер range.
Примеры
iex> Range.size(1..10) 10 iex> Range.size(1..10//2) 5 iex> Range.size(1..10//3) 4 iex> Range.size(1..10//-1) 0 iex> Range.size(10..1) 10 iex> Range.size(10..1//-1) 10 iex> Range.size(10..1//-2) 5 iex> Range.size(10..1//-3) 4 iex> Range.size(10..1//1) 0
© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.14.1/Range.html