Spec-Zone.ru › Elixir 1.15

Диапазон

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

Наиболее распространённый способ создания и сопоставления с диапазонами — это обозначения first..last и first..last//step, автоматически импортированные из Kernel:

iex> 1 in 1..10
true
iex> 5 in 1..10
true
iex> 10 in 1..10
true

Диапазоны всегда включают конечные значения. Когда определён шаг, целые числа будут принадлежать диапазону только в том случае, если они соответствуют шагу:

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()
шаг()
t()
t(начало, конец)

Функции

disjoint?(range1, range2)

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

new(начало, конец)

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

new(начало, конец, шаг)

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

shift(аргумент, количество_шагов)

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

size(диапазон)

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

split(диапазон, разделить)

Разделяет диапазон на два.

to_list(аргумент1)

Преобразует диапазон в список.

limit()Источник

@type limit() :: integer()

шаг()Источник

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

t()Источник

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

t(начало, конец)Источник

@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 is 29
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, 50..8//-21)
false
iex> Range.disjoint?(1..28//14, 8..28//21)
true

# First element in common is 14
iex> Range.disjoint?(2..28//3, 9..28//5)
false
iex> Range.disjoint?(26..2//-3, 29..9//-5)
false

# Starting from the back without alignment
iex> Range.disjoint?(27..11//-3, 30..0//-7)
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
iex> Range.shift(10..0//-2, 2)
6..-4//-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

split(range, split)Source

Делит диапазон на две части.

Возвращает кортеж из двух элементов.

Если split меньше количества элементов в диапазоне, первый элемент диапазона будет содержать split элементов, а второй — все оставшиеся.

Если split больше количества элементов в диапазоне, второй диапазон в кортеже выведет ноль элементов.

Примеры

Возрастающие диапазоны:

iex> Range.split(1..5, 2)
{1..2, 3..5}

iex> Range.split(1..5//2, 2)
{1..3//2, 5..5//2}

iex> Range.split(1..5//2, 0)
{1..-1//2, 1..5//2}

iex> Range.split(1..5//2, 10)
{1..5//2, 7..5//2}

Убывающие диапазоны также можно разделить:

iex> Range.split(5..1//-1, 2)
{5..4//-1, 3..1//-1}

iex> Range.split(5..1//-2, 2)
{5..3//-2, 1..1//-2}

iex> Range.split(5..1//-2, 0)
{5..7//-2, 5..1//-2}

iex> Range.split(5..1//-2, 10)
{5..1//-2, -1..1//-2}

Пустые диапазоны сохраняют своё свойство, но всё равно возвращают пустые диапазоны:

iex> Range.split(2..5//-1, 2)
{2..3//-1, 4..5//-1}

iex> Range.split(2..5//-1, 10)
{2..3//-1, 4..5//-1}

iex> Range.split(5..2//1, 2)
{5..4//1, 3..2//1}

iex> Range.split(5..2//1, 10)
{5..4//1, 3..2//1}

Если число для разделения отрицательно, оно разделяет с конца:

iex> Range.split(1..5, -2)
{1..3, 4..5}

iex> Range.split(5..1//-1, -2)
{5..3//-1, 2..1//-1}

Если оно отрицательно и больше элементов в диапазоне, первый элемент кортежа будет пустым диапазоном:

iex> Range.split(1..5, -10)
{1..0//1, 1..5}

iex> Range.split(5..1//-1, -10)
{5..6//-1, 5..1//-1}

Свойства

При разделении диапазона наблюдаются следующие свойства. Если split(input) возвращает {left, right}, у нас есть:

assert input.first == left.first
assert input.last == right.last
assert input.step == left.step
assert input.step == right.step
assert Range.size(input) == Range.size(left) + Range.size(right)

to_list(arg1)Source

Преобразует диапазон в список.

© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.15.4/Range.html

Spec-Zone.ru

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