Spec-Zone.ru › Elixir 1.14

Диапазон

Диапазоны представляют собой последовательность нуля, одного или многих возрастающих или убывающих целых чисел с общей разностью, называемой шагом.

Наиболее распространённый способ создания и сопоставления с диапазонами — использование обозначений 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 использует логику, основанную только на конечных точках, и не материализует весь список целых чисел.

Краткое описание

Типы

limit()
step()
t()
t(first, last)

Функции

disjoint?(range1, range2)

Проверяет, являются ли два диапазона непересекающимися.

new(first, last)

Создаёт новый диапазон.

new(first, last, step)

Создаёт новый диапазон с step.

shift(arg, steps_to_shift)

Смещает диапазон на указанное количество шагов.

size(range)

Возвращает размер range.

Типы

limit()Source

@type limit() :: integer()

step()Source

@type step() :: pos_integer() | neg_integer()

t()Source

@type t() :: %Range{first: limit(), last: limit(), step: step()}

t(first, last)Source

@type t(first, last) :: %Range{first: first, last: last, step: step()}

Функции

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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API