Spec-Zone.ru › Elixir 1.3

Поток

Модуль для создания и комбинирования потоков.

Потоки — это комбинируемые, ленивые перечислимые объекты. Любой перечислимый объект, генерирующий элементы один за другим во время перечисления, называется потоком. Например, Range в Elixir — это поток:

iex> range = 1..5
1..5
iex> Enum.map range, &(&1 * 2)
[2, 4, 6, 8, 10]

В примере выше, при применении map к диапазону, элементы создавались один за другим во время перечисления. Модуль Stream позволяет нам отобразить диапазон, не вызывая его перечисления:

iex> range = 1..3
iex> stream = Stream.map(range, &(&1 * 2))
iex> Enum.map(stream, &(&1 + 1))
[3, 5, 7]

Обратите внимание, что мы начали с диапазона, а затем создали поток, который предназначен для умножения каждого элемента в диапазоне на 2. На этом этапе вычислений не проводилось. Только при вызове Enum.map/2 мы фактически перечисляем каждый элемент в диапазоне, умножая его на 2 и добавляя 1. Мы говорим, что функции в Stream являются ленивыми, а функции в Enum — жадными.

Благодаря лени, потоки полезны при работе с большими (или даже бесконечными) коллекциями. При объединении множества операций с Enum создаются промежуточные списки, в то время как Stream создаёт рецепт вычислений, которые выполняются в более поздний момент. Давайте посмотрим другой пример:

1..3
|> Enum.map(&IO.inspect(&1))
|> Enum.map(&(&1 * 2))
|> Enum.map(&IO.inspect(&1))
1
2
3
2
4
6
#=> [2, 4, 6]

Обратите внимание, что сначала мы вывели каждый элемент в списке, затем умножили каждый элемент на 2 и, наконец, вывели каждое новое значение. В этом примере список был перечислен трижды. Давайте посмотрим пример с потоками:

stream = 1..3
|> Stream.map(&IO.inspect(&1))
|> Stream.map(&(&1 * 2))
|> Stream.map(&IO.inspect(&1))
Enum.to_list(stream)
1
2
2
4
3
6
#=> [2, 4, 6]

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

Вот что мы имели в виду, когда ранее говорили, что потоки — это комбинируемые, ленивые перечислимые объекты. Обратите внимание, что мы можем вызывать Stream.map/2 несколько раз, эффективно комбинируя потоки и сохраняя их ленивыми. Вычисления выполняются только при вызове функции из модуля Enum.

Создание потоков

В стандартной библиотеке Elixir существует много функций, возвращающих потоки, некоторые примеры:

  • IO.stream/2 - потоки входных строк, по одной
  • URI.query_decoder/1 - декодирует строку запроса, пару за парой

Этот модуль также предоставляет множество удобных функций для создания потоков, таких как Stream.cycle/1, Stream.unfold/2, Stream.resource/3 и другие.

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

Сводка

Типы

acc()
default()
element()
index()

Функции

chunk(enum, n)

Сокращение для chunk(enum, n, n)

chunk(enum, n, step, leftover \\ nil)

Потоки перечислимого объекта в блоках, содержащих по n элементов каждый, где каждый новый блок начинается с step элементов в перечислимом объекте

chunk_by(enum, fun)

Блокирует enum путём буферизации элементов, для которых fun возвращает одинаковое значение, и выводит их только тогда, когда fun возвращает новое значение или enum завершается

concat(enumerables)

Создаёт поток, перечисляющий каждый перечислимый объект в перечислимом объекте

concat(first, second)

Создаёт поток, перечисляющий первый аргумент, за которым следует второй

cycle(enumerable)

Создаёт поток, циклически перечисляющий заданный перечислимый объект, бесконечно

dedup(enum)

Создаёт поток, который выводит элементы только если они отличаются от последнего выведенного элемента

dedup_by(enum, fun)

Создаёт поток, который выводит элементы только если результат вызова fun на элементе отличается от (сохранённого) результата вызова fun на последнем выведенном элементе

drop(enum, n)

Лениво пропускает следующие n элементов из перечислимого объекта

drop_every(enum, nth)

Создаёт поток, пропускающий каждый nth элемент из перечислимого объекта

drop_while(enum, fun)

Лениво пропускает элементы перечислимого объекта, пока данная функция возвращает true

each(enum, fun)

Выполняет данную функцию для каждого элемента

filter(enum, fun)

Создаёт поток, фильтрующий элементы в соответствии с данной функцией при перечислении

filter_map(enum, filter, mapper)

Создаёт поток, фильтрующий, а затем отображающий элементы в соответствии с заданными функциями

flat_map(enum, mapper)

Создаёт поток, который применит данную функцию при перечислении и распакует результат, но только на один уровень вглубь

interval(n)

Создаёт поток, который выводит значение через заданный период n миллисекунд

into(enum, collectable, transform \\ fn x -> x end)

Вставляет значения потока в заданный коллектор как побочный эффект

iterate(start_value, next_fun)

Выводит последовательность значений, начиная с start_value. Последующие значения генерируются путём вызова next_fun на предыдущем значении

map(enum, fun)

Создаёт поток, который применит данную функцию при перечислении

reject(enum, fun)

Создаёт поток, который отбрасывает элементы в соответствии с данной функцией при перечислении

repeatedly(generator_fun)

Возвращает поток, генерируемый путём вызова generator_fun многократно

resource(start_fun, next_fun, after_fun)

Выводит последовательность значений для данного ресурса

run(stream)

Запускает данный поток

scan(enum, fun)

Создаёт поток, который применяет данную функцию к каждому элементу, выводит результат и использует тот же результат в качестве аккумулятора для следующего вычисления

scan(enum, acc, fun)

Создаёт поток, который применяет данную функцию к каждому элементу, выводит результат и использует тот же результат в качестве аккумулятора для следующего вычисления. Использует указанное acc в качестве начального значения

take(enum, count)

Лениво берёт следующие count элементов из перечислимого объекта и останавливает перечисление

take_every(enum, nth)

Создаёт поток, который берёт каждый nth элемент из перечислимого объекта

take_while(enum, fun)

Лениво берёт элементы перечислимого объекта, пока данная функция возвращает true

timer(n)

Создаёт поток, который выводит единственное значение после n миллисекунд

transform(enum, acc, reducer)

Преобразует существующий поток

transform(enum, start_fun, reducer, after_fun)

Преобразует существующий поток с функциями начала и окончания

unfold(next_acc, next_fun)

Выводит последовательность значений для данного аккумулятора

uniq(enum, fun \\ fn x -> x end)

Создаёт поток, который выводит элементы только если они уникальны

with_index(enum, offset \\ 0)

Создаёт поток, где каждый элемент в перечислимом объекте будет обернут в кортеж вместе с его индексом

zip(left, right)

Лениво объединяет два набора

Типы

acc()

acc() :: any

default()

default() :: any

element()

element() :: any

index()

index() :: non_neg_integer

Функции

chunk(enum, n)

chunk(Enumerable.t, non_neg_integer) :: Enumerable.t

Сокращение для chunk(enum, n, n).

chunk(enum, n, step, leftover \\ nil)

chunk(Enumerable.t, pos_integer, pos_integer, Enumerable.t | nil) :: Enumerable.t

Потоковая обработка перечислимого объекта по частям, содержащих по n элементов в каждой, где каждая новая часть начинается с step элементов в перечислимом объекте.

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

Примеры

iex> Stream.chunk([1, 2, 3, 4, 5, 6], 2) |> Enum.to_list
[[1, 2], [3, 4], [5, 6]]

iex> Stream.chunk([1, 2, 3, 4, 5, 6], 3, 2) |> Enum.to_list
[[1, 2, 3], [3, 4, 5]]

iex> Stream.chunk([1, 2, 3, 4, 5, 6], 3, 2, [7]) |> Enum.to_list
[[1, 2, 3], [3, 4, 5], [5, 6, 7]]

iex> Stream.chunk([1, 2, 3, 4, 5, 6], 3, 3, []) |> Enum.to_list
[[1, 2, 3], [4, 5, 6]]

chunk_by(enum, fun)

chunk_by(Enumerable.t, (element -> any)) :: Enumerable.t

Разбивает перечислимый объект на части, буферизируя элементы, для которых fun возвращает то же значение, и передавая их только тогда, когда fun возвращает новое значение или перечисление завершается.

Примеры

iex> stream = Stream.chunk_by([1, 2, 2, 3, 4, 4, 6, 7, 7], &(rem(&1, 2) == 1))
iex> Enum.to_list(stream)
[[1], [2, 2], [3], [4, 4, 6], [7, 7]]

concat(enumerables)

concat(Enumerable.t) :: Enumerable.t

Создаёт поток, перечисляющий каждый перечислимый объект в перечислимом объекте.

Примеры

iex> stream = Stream.concat([1..3, 4..6, 7..9])
iex> Enum.to_list(stream)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

concat(first, second)

concat(Enumerable.t, Enumerable.t) :: Enumerable.t

Создаёт поток, перечисляющий первый аргумент, а затем второй.

Примеры

iex> stream = Stream.concat(1..3, 4..6)
iex> Enum.to_list(stream)
[1, 2, 3, 4, 5, 6]

iex> stream1 = Stream.cycle([1, 2, 3])
iex> stream2 = Stream.cycle([4, 5, 6])
iex> stream = Stream.concat(stream1, stream2)
iex> Enum.take(stream, 6)
[1, 2, 3, 1, 2, 3]

cycle(enumerable)

cycle(Enumerable.t) :: Enumerable.t

Создаёт поток, циклически перечисляющий заданный перечислимый объект бесконечно.

Примеры

iex> stream = Stream.cycle([1, 2, 3])
iex> Enum.take(stream, 5)
[1, 2, 3, 1, 2]

dedup(enum)

dedup(Enumerable.t) :: Enumerable.t

Создаёт поток, который передаёт элементы только в том случае, если они отличаются от последнего переданного элемента.

Эта функция только сохраняет последний переданный элемент.

Элементы сравниваются с использованием ===.

Примеры

iex> Stream.dedup([1, 2, 3, 3, 2, 1]) |> Enum.to_list
[1, 2, 3, 2, 1]

dedup_by(enum, fun)

dedup_by(Enumerable.t, (element -> term)) :: Enumerable.t

Создаёт поток, который передаёт элементы только в том случае, если результат вызова fun для элемента отличается от результата вызова fun для последнего переданного элемента.

Примеры

iex> Stream.dedup_by([{1, :x}, {2, :y}, {2, :z}, {1, :x}], fn {x, _} -> x end) |> Enum.to_list
[{1, :x}, {2, :y}, {1, :x}]

drop(enum, n)

drop(Enumerable.t, non_neg_integer) :: Enumerable.t

Лениво отбрасывает следующие n элементы из перечислимого объекта.

Если передан отрицательный n, он отбросит последние n элементов из коллекции. Обратите внимание, что механизм, с помощью которого это реализовано, отложит передачу любого элемента до тех пор, пока не будут переданы ещё n элементов перечисления.

Примеры

iex> stream = Stream.drop(1..10, 5)
iex> Enum.to_list(stream)
[6, 7, 8, 9, 10]

iex> stream = Stream.drop(1..10, -5)
iex> Enum.to_list(stream)
[1, 2, 3, 4, 5]

drop_every(enum, nth)

drop_every(Enumerable.t, non_neg_integer) :: Enumerable.t

Создаёт поток, отбрасывающий каждый nth элемент из перечислимого объекта.

Первый элемент всегда отбрасывается, если nth не 0.

nth должно быть целым неотрицательным числом, в противном случае будет выброшено исключение FunctionClauseError.

Примеры

iex> stream = Stream.drop_every(1..10, 2)
iex> Enum.to_list(stream)
[2, 4, 6, 8, 10]

iex> stream = Stream.drop_every(1..1000, 1)
iex> Enum.to_list(stream)
[]

iex> stream = Stream.drop_every([1, 2, 3, 4, 5], 0)
iex> Enum.to_list(stream)
[1, 2, 3, 4, 5]

drop_while(enum, fun)

drop_while(Enumerable.t, (element -> as_boolean(term))) :: Enumerable.t

Лениво отбрасывает элементы перечислимого объекта, пока данная функция возвращает true.

Примеры

iex> stream = Stream.drop_while(1..10, &(&1 <= 5))
iex> Enum.to_list(stream)
[6, 7, 8, 9, 10]

each(enum, fun)

each(Enumerable.t, (element -> term)) :: Enumerable.t

Выполняет заданную функцию для каждого элемента.

Полезно для добавления побочных эффектов (например, печати) в поток.

Примеры

iex> stream = Stream.each([1, 2, 3], fn(x) -> send self, x end)
iex> Enum.to_list(stream)
iex> receive do: (x when is_integer(x) -> x)
1
iex> receive do: (x when is_integer(x) -> x)
2
iex> receive do: (x when is_integer(x) -> x)
3

filter(enum, fun)

filter(Enumerable.t, (element -> as_boolean(term))) :: Enumerable.t

Создаёт поток, отфильтровывающий элементы в соответствии с заданной функцией при перечислении.

Примеры

iex> stream = Stream.filter([1, 2, 3], fn(x) -> rem(x, 2) == 0 end)
iex> Enum.to_list(stream)
[2]

filter_map(enum, filter, mapper)

filter_map(Enumerable.t, (element -> as_boolean(term)), (element -> any)) :: Enumerable.t

Создаёт поток, отфильтровывающий и затем отображающий элементы в соответствии с заданными функциями.

Существует для симметрии с Enum.filter_map/3.

Примеры

iex> stream = Stream.filter_map(1..6, fn(x) -> rem(x, 2) == 0 end, &(&1 * 2))
iex> Enum.to_list(stream)
[4, 8, 12]

flat_map(enum, mapper)

flat_map(Enumerable.t, (element -> Enumerable.t)) :: Enumerable.t

Создаёт поток, который применит заданную функцию к перечислению и сплющит результат, но только на один уровень.

Примеры

iex> stream = Stream.flat_map([1, 2, 3], fn(x) -> [x, x * 2] end)
iex> Enum.to_list(stream)
[1, 2, 2, 4, 3, 6]

iex> stream = Stream.flat_map([1, 2, 3], fn(x) -> [[x]] end)
iex> Enum.to_list(stream)
[[1], [2], [3]]

interval(n)

interval(non_neg_integer) :: Enumerable.t

Создаёт поток, который передаёт значение через заданный интервал n миллисекунд.

Передаваемые значения — это увеличивающийся счётчик, начинающийся с 0. Данная операция блокирует вызывающий объект заданным интервалом при каждом передаваемом элементе.

Примеры

iex> Stream.interval(10) |> Enum.take(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

into(enum, collectable, transform \\ fn x -> x end)

Вставляет значения потока в заданный объект-сборщик как побочный эффект.

Эта функция часто используется с run/1, так как любое вычисление откладывается до выполнения потока. См. пример в run/1.

iterate(start_value, next_fun)

iterate(element, (element -> element)) :: Enumerable.t

Передаёт последовательность значений, начиная с start_value. Последующие значения генерируются путём вызова next_fun с предыдущим значением.

Примеры

iex> Stream.iterate(0, &(&1+1)) |> Enum.take(5)
[0, 1, 2, 3, 4]

map(enum, fun)

map(Enumerable.t, (element -> any)) :: Enumerable.t

Создаёт поток, который применит заданную функцию к перечислению.

Примеры

iex> stream = Stream.map([1, 2, 3], fn(x) -> x * 2 end)
iex> Enum.to_list(stream)
[2, 4, 6]

reject(enum, fun)

reject(Enumerable.t, (element -> as_boolean(term))) :: Enumerable.t

Создаёт поток, отбрасывающий элементы в соответствии с заданной функцией при перечислении.

Примеры

iex> stream = Stream.reject([1, 2, 3], fn(x) -> rem(x, 2) == 0 end)
iex> Enum.to_list(stream)
[1, 3]

repeatedly(generator_fun)

repeatedly((() -> element)) :: Enumerable.t

Возвращает поток, сгенерированный путём многократного вызова generator_fun.

Примеры

# Although not necessary, let's seed the random algorithm
iex> :rand.seed(:exsplus, {1, 2, 3})
iex> Stream.repeatedly(&:rand.uniform/0) |> Enum.take(3)
[0.40502929729990744, 0.45336720247823126, 0.04094511692041057]

resource(start_fun, next_fun, after_fun)

resource((() -> acc), (acc -> {[element], acc} | {:halt, acc}), (acc -> term)) :: Enumerable.t

Передаёт последовательность значений для данного ресурса.

Аналогично transform/3, но начальное накопленное значение вычисляется лениво через start_fun и выполняет after_fun в конце перечисления (в случае успеха и неудачи).

Последующие значения генерируются путём вызова next_fun с предыдущим накопителем (начальное значение — результат, возвращённый start_fun). Он должен возвращать кортеж, содержащий список передаваемых элементов и следующий накопитель. Перечисление завершается, если он возвращает {:halt, acc}.

Как следует из названия, эта функция полезна для потоковой передачи значений из ресурсов.

Примеры

Stream.resource(fn -> File.open!("sample") end,
                fn file ->
                  case IO.read(file, :line) do
                    data when is_binary(data) -> {[data], file}
                    _ -> {:halt, file}
                  end
                end,
                fn file -> File.close(file) end)

run(stream)

run(Enumerable.t) :: :ok

Выполняет заданный поток.

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

Примеры

Открыть файл, заменить все # на % и передать в другой файл без загрузки всего файла в память:

stream = File.stream!("code")
|> Stream.map(&String.replace(&1, "#", "%"))
|> Stream.into(File.stream!("new"))
|> Stream.run

Никаких вычислений не будет произведено, пока мы не вызовем одну из функций Enum или Stream.run/1.

scan(enum, fun)

scan(Enumerable.t, (element, acc -> any)) :: Enumerable.t

Создаёт поток, который применяет заданную функцию к каждому элементу, передаёт результат и использует тот же результат в качестве накопителя для следующего вычисления.

Примеры

iex> stream = Stream.scan(1..5, &(&1 + &2))
iex> Enum.to_list(stream)
[1, 3, 6, 10, 15]

scan(enum, acc, fun)

scan(Enumerable.t, acc, (element, acc -> any)) :: Enumerable.t

Создаёт поток, который применяет заданную функцию к каждому элементу, передаёт результат и использует тот же результат в качестве накопителя для следующего вычисления. Использует заданное acc в качестве начального значения.

Примеры

iex> stream = Stream.scan(1..5, 0, &(&1 + &2))
iex> Enum.to_list(stream)
[1, 3, 6, 10, 15]

take(enum, count)

take(Enumerable.t, integer) :: Enumerable.t

Лениво берёт следующие count элементов из перечислимого объекта и останавливает перечисление.

Если задано отрицательное значение count, будут взяты последние count значения. Для этого коллекция полностью перечисляется, сохраняя до 2 * count элементов в памяти. После достижения конца коллекции будут выполнены последние count элементы. Поэтому использование отрицательного значения count для бесконечной коллекции никогда не вернёт результат.

Примеры

iex> stream = Stream.take(1..100, 5)
iex> Enum.to_list(stream)
[1, 2, 3, 4, 5]

iex> stream = Stream.take(1..100, -5)
iex> Enum.to_list(stream)
[96, 97, 98, 99, 100]

iex> stream = Stream.cycle([1, 2, 3]) |> Stream.take(5)
iex> Enum.to_list(stream)
[1, 2, 3, 1, 2]

take_every(enum, nth)

take_every(Enumerable.t, non_neg_integer) :: Enumerable.t

Создаёт поток, который берёт каждый nth элемент из перечислимого объекта.

Первый элемент всегда включается, если только nth не равен 0.

nth должно быть неотрицательным целым числом, в противном случае будет выброшено исключение FunctionClauseError.

Примеры

iex> stream = Stream.take_every(1..10, 2)
iex> Enum.to_list(stream)
[1, 3, 5, 7, 9]

iex> stream = Stream.take_every([1, 2, 3, 4, 5], 1)
iex> Enum.to_list(stream)
[1, 2, 3, 4, 5]

iex> stream = Stream.take_every(1..1000, 0)
iex> Enum.to_list(stream)
[]

take_while(enum, fun)

take_while(Enumerable.t, (element -> as_boolean(term))) :: Enumerable.t

Лениво берёт элементы перечислимого объекта, пока заданная функция возвращает true.

Примеры

iex> stream = Stream.take_while(1..100, &(&1 <= 5))
iex> Enum.to_list(stream)
[1, 2, 3, 4, 5]

timer(n)

timer(non_neg_integer) :: Enumerable.t

Создаёт поток, который испускает одно значение после n миллисекунд.

Используемое значение равно 0. Эта операция заблокирует вызывающую функцию на заданное время до тех пор, пока элемент не будет передан в поток.

Примеры

iex> Stream.timer(10) |> Enum.to_list
[0]

transform(enum, acc, reducer)

transform(Enumerable.t, acc, fun) :: Enumerable.t when fun: (element, acc -> {Enumerable.t, acc} | {:halt, acc}), acc: any

Преобразует существующий поток.

Ожидает аккумулирующее значение и функцию, которая получает каждый элемент потока и аккумулирующее значение, и должна вернуть кортеж, содержащий новый поток (часто список) с новым аккумулирующим значением или кортеж с :halt в качестве первого элемента и аккумулирующим значением во втором.

Примечание: эта функция похожа на Enum.flat_map_reduce/3, за исключением того, что последняя возвращает как плоский список, так и аккумулирующее значение, а эта возвращает только поток.

Stream.transform/3 полезна, так как её можно использовать в качестве основы для реализации многих функций, определённых в этом модуле. Например, мы можем реализовать Stream.take(enum, n) следующим образом:

iex> enum = 1..100
iex> n = 3
iex> stream = Stream.transform(enum, 0, fn i, acc ->
...>   if acc < n, do: {[i], acc + 1}, else: {:halt, acc}
...> end)
iex> Enum.to_list(stream)
[1, 2, 3]

transform(enum, start_fun, reducer, after_fun)

transform(Enumerable.t, (() -> acc), fun, (acc -> term)) :: Enumerable.t when fun: (element, acc -> {Enumerable.t, acc} | {:halt, acc}), acc: any

Преобразует существующий поток с функциями начала и окончания.

Аккумулирующее значение вычисляется только при запуске преобразования. Также позволяет указать функцию `after`, которая вызывается, когда поток останавливается или завершается.

Эта функция может быть представлена как комбинация Stream.resource/3 и Stream.transform/3.

unfold(next_acc, next_fun)

unfold(acc, (acc -> {element, acc} | nil)) :: Enumerable.t

Испускает последовательность значений для данного аккумулирующего значения.

Последовательные значения генерируются путём вызова next_fun с предыдущим аккумулирующим значением, и оно должно вернуть кортеж с текущим значением и следующим аккумулирующим значением. Перечисление завершается, если оно возвращает nil.

Примеры

iex> Stream.unfold(5, fn 0 -> nil; n -> {n, n-1} end) |> Enum.to_list()
[5, 4, 3, 2, 1]

uniq(enum, fun \\ fn x -> x end)

uniq(Enumerable.t, (element -> term)) :: Enumerable.t

Создаёт поток, который испускает только уникальные элементы.

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

Примеры

iex> Stream.uniq([1, 2, 3, 3, 2, 1]) |> Enum.to_list
[1, 2, 3]

iex> Stream.uniq([{1, :x}, {2, :y}, {2, :z}, {1, :x}], fn {x, _} -> x end) |> Enum.to_list
[{1, :x}, {2, :y}]

with_index(enum, offset \\ 0)

with_index(Enumerable.t, integer) :: Enumerable.t

Создаёт поток, где каждый элемент в перечислимом объекте будет заключён в кортеж вместе с его индексом.

Примеры

iex> stream = Stream.with_index([1, 2, 3])
iex> Enum.to_list(stream)
[{1, 0}, {2, 1}, {3, 2}]

iex> stream = Stream.with_index([1, 2, 3], 3)
iex> Enum.to_list(stream)
[{1, 3}, {2, 4}, {3, 5}]

zip(left, right)

zip(Enumerable.t, Enumerable.t) :: Enumerable.t

Лениво объединяет две коллекции.

Объединение завершается, как только любая перечисляемая коллекция завершается.

Примеры

iex> concat = Stream.concat(1..3, 4..6)
iex> cycle  = Stream.cycle([:a, :b, :c])
iex> Stream.zip(concat, cycle) |> Enum.to_list
[{1, :a}, {2, :b}, {3, :c}, {4, :a}, {5, :b}, {6, :c}]

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

Spec-Zone.ru

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