sequtils
Хотя в названии этого модуля есть seq, он реализует операции не только для типа seq, но и для трёх встроенных типов контейнеров под openArray зонтиком:
- последовательности
- строки
- массивы
Модуль системы определяет несколько общих функций, таких как:
-
newSeq[T]для создания новых последовательностей типаT -
@для преобразования массивов и строк в последовательности -
addдля добавления новых элементов в строки и последовательности -
&для конкатенации строк и последовательностей -
in(псевдоним дляcontains) иnotinдля проверки наличия элемента в контейнере
Этот модуль опирается на это, предоставляя дополнительную функциональность в виде процедур, итераторов и шаблонов, вдохновлённых функциональными языками программирования.
Для функционального стиля программирования у вас есть различные варианты:
- макрос sugar.collect
- передача анонимной процедуры
- импорт модуля sugar и использование => макроса
- использование ...Шаблонов It (mapIt, filterIt и т.д.)
Цепочечное вызов функций возможно благодаря синтаксису вызова метода.
import sequtils, sugar
# Creating a sequence from 1 to 10, multiplying each member by 2,
# keeping only the members which are not divisible by 6.
let
foo = toSeq(1..10).map(x => x*2).filter(x => x mod 6 != 0)
bar = toSeq(1..10).mapIt(it*2).filterIt(it mod 6 != 0)
baz = collect(newSeq):
for i in 1..10:
let j = 2*i
if j mod 6 != 0:
j
doAssert foo == bar
doAssert foo == baz
echo foo # @[2, 4, 8, 10, 14, 16, 20]
echo foo.any(x => x > 17) # true
echo bar.allIt(it < 20) # false
echo foo.foldl(a + b) # 74; sum of all members
import sequtils from strutils import join let vowels = @"aeiou" # creates a sequence @['a', 'e', 'i', 'o', 'u'] foo = "sequtils is an awesome module" echo foo.filterIt(it notin vowels).join # "sqtls s n wsm mdl"
См. также:
- модуль strutils для общих функций строк
- модуль sugar для макросов синтаксического сахара
- модуль algorithm для общих алгоритмов
- модуль json для структуры, позволяющей гетерогенные члены
Импорты
- since, macros
Процедуры
proc concat[T](seqs: varargs[seq[T]]): seq[T]
-
Принимает несколько элементов последовательностей и возвращает их внутри новой последовательности. Все последовательности должны быть одного типа.
См. также:
- процедуру distribute для обратной операции
Пример:
let s1 = @[1, 2, 3] s2 = @[4, 5] s3 = @[6, 7] total = concat(s1, s2, s3) assert total == @[1, 2, 3, 4, 5, 6, 7]
Исходный код Редактировать proc count[T](s: openArray[T]; x: T): int
- Возвращает количество вхождений элемента
xв контейнереs.Пример:
let a = @[1, 2, 2, 3, 2, 4, 2] b = "abracadabra" assert count(a, 2) == 4 assert count(a, 99) == 0 assert count(b, 'r') == 2
Исходный код Редактировать proc cycle[T](s: openArray[T]; n: Natural): seq[T]
- Возвращает новую последовательность с элементами контейнера
sповторённымиnраз.nдолжно быть неотрицательным числом (ноль или больше).Пример:
let s = @[1, 2, 3] total = s.cycle(3) assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
Исходный код Редактировать proc repeat[T](x: T; n: Natural): seq[T]
- Возвращает новую последовательность с элементом
xповторённымnраз.nдолжно быть неотрицательным числом (ноль или больше).Пример:
let total = repeat(5, 3) assert total == @[5, 5, 5]
Исходный код Редактировать proc deduplicate[T](s: openArray[T]; isSorted: bool = false): seq[T]
-
Возвращает новую последовательность без дубликатов.
Установив необязательный аргумент
isSortedв значениеtrue(по умолчанию: false), используется более быстрый алгоритм удаления дубликатов.Пример:
let dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4] dup2 = @["a", "a", "c", "d", "d"] unique1 = deduplicate(dup1) unique2 = deduplicate(dup2, isSorted = true) assert unique1 == @[1, 3, 4, 2, 8] assert unique2 == @["a", "c", "d"]
Исходный код Редактировать proc minIndex[T](s: openArray[T]): int
- Возвращает индекс минимального значения в
s.Tдолжен иметь оператор<.Пример:
let a = @[1, 2, 3, 4] b = @[6, 5, 4, 3] c = [2, -7, 8, -5] d = "ziggy" assert minIndex(a) == 0 assert minIndex(b) == 3 assert minIndex(c) == 1 assert minIndex(d) == 2
Исходный код Редактировать proc maxIndex[T](s: openArray[T]): int
- Возвращает индекс максимального значения в
s.Tдолжен иметь оператор<.Пример:
let a = @[1, 2, 3, 4] b = @[6, 5, 4, 3] c = [2, -7, 8, -5] d = "ziggy" assert maxIndex(a) == 3 assert maxIndex(b) == 0 assert maxIndex(c) == 2 assert maxIndex(d) == 0
Исходный код Редактировать proc zip[S, T](s1: openArray[S]; s2: openArray[T]): seq[(S, T)]
-
Возвращает новую последовательность, являющуюся комбинацией двух входных контейнеров.
Входные контейнеры могут быть разных типов. Если один контейнер короче, оставшиеся элементы в более длинном контейнере отбрасываются.
Примечание: Для Nim 1.0.x и более старых версий,
zipвозвращала seq именованных кортежей с полямиaиb. Для версий Nim 1.1.x и более новых,zipвозвращает seq неименованных кортежей.Пример:
let short = @[1, 2, 3] long = @[6, 5, 4, 3, 2, 1] words = @["one", "two", "three"] letters = "abcd" zip1 = zip(short, long) zip2 = zip(short, words) assert zip1 == @[(1, 6), (2, 5), (3, 4)] assert zip2 == @[(1, "one"), (2, "two"), (3, "three")] assert zip1[2][0] == 3 assert zip2[1][1] == "two" when (NimMajor, NimMinor) <= (1, 0): let zip3 = zip(long, letters) assert zip3 == @[(a: 6, b: 'a'), (5, 'b'), (4, 'c'), (3, 'd')] assert zip3[0].b == 'a' else: let zip3: seq[tuple[num: int, letter: char]] = zip(long, letters) assert zip3 == @[(6, 'a'), (5, 'b'), (4, 'c'), (3, 'd')] assert zip3[0].letter == 'a'Исходный код Редактировать proc unzip[S, T](s: openArray[(S, T)]): (seq[S], seq[T])
- Возвращает кортеж из двух последовательностей, полученных из последовательности пар (кортежей) из двух элементов.
Пример:
let zipped = @[(1, 'a'), (2, 'b'), (3, 'c')] unzipped1 = @[1, 2, 3] unzipped2 = @['a', 'b', 'c'] assert zipped.unzip() == (unzipped1, unzipped2) assert zip(unzipped1, unzipped2).unzip() == (unzipped1, unzipped2)
Исходный код Редактировать proc distribute[T](s: seq[T]; num: Positive; spread = true): seq[seq[T]]
-
Разбивает и распределяет последовательность
sнаnumподпоследовательностей.Возвращает последовательность из
numпоследовательностей. Для некоторых значений входных данных это обратная операция к процедуре concat. Входная последовательностьsможет быть пустой, что приведет к созданиюnumпустых последовательностей.Если
spreadложно и длинаsне кратнаnum, процедура максимально заполнит первую подпоследовательность1 + len(s) div numэлементами, оставив оставшиеся элементы в последней последовательности.С другой стороны, если
spreadистинно, процедура равномерно распределит остаток от деления по всем последовательностям, что делает результат более подходящим для многопоточности, когда вы передаете равные по размеру задачи в пул потоков и хотите максимизировать использование ядер.Пример:
let numbers = @[1, 2, 3, 4, 5, 6, 7] assert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]] assert numbers.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]] assert numbers.distribute(6)[0] == @[1, 2] assert numbers.distribute(6)[1] == @[3]
Исходный код Редактировать proc map[T, S](s: openArray[T]; op: proc (x: T): S {...}{.closure.}): seq[S] {...}{.inline.}-
Возвращает новую последовательность с результатами применения процедуры
opк каждому элементу в контейнереs.Так как вход не изменяется, вы можете использовать эту функцию для преобразования типа элементов в входном контейнере.
Вместо использования
mapиfilter, рассмотрите использование макросаcollectиз модуляsugar.См. также:
- макрос sugar.collect
- шаблон mapIt
- процедуру apply для варианта на месте
Пример:
let a = @[1, 2, 3, 4] b = map(a, proc(x: int): string = $x) assert b == @["1", "2", "3", "4"]
Исходный код Редактировать proc apply[T](s: var openArray[T]; op: proc (x: var T) {...}{.closure.}) {...}{.inline.}-
Применяет
opк каждому элементу вs, изменяя его напрямую.Обратите внимание, что контейнер
sдолжен быть объявлен какvar, и требуется, чтобы типы входных и выходных данных были одинаковыми, так какsизменяется на месте. Параметрическая функция принимает параметр типаvar T.См. также:
Пример:
var a = @["1", "2", "3", "4"] apply(a, proc(x: var string) = x &= "42") assert a == @["142", "242", "342", "442"]
Исходный код Редактировать proc apply[T](s: var openArray[T]; op: proc (x: T): T {...}{.closure.}) {...}{.inline.}-
Применяет
opк каждому элементу вs, изменяя его напрямую.Обратите внимание, что контейнер
sдолжен быть объявлен какvar, и требуется, чтобы типы входных и выходных данных были одинаковыми, так какsизменяется на месте. Параметрическая функция принимает и возвращает переменную типаT.См. также:
Пример:
var a = @["1", "2", "3", "4"] apply(a, proc(x: string): string = x & "42") assert a == @["142", "242", "342", "442"]
Исходный код Редактировать proc apply[T](s: openArray[T]; op: proc (x: T) {...}{.closure.}) {...}{.inline.}- То же, что и
apply, но для процедур, которые не возвращают и не изменяютsнапрямую.Пример:
apply([0, 1, 2, 3, 4], proc(item: int) = echo item)
Исходный код Редактировать proc filter[T](s: openArray[T]; pred: proc (x: T): bool {...}{.closure.}): seq[T] {...}{. inline.}-
Возвращает новую последовательность со всеми элементами
s, которые удовлетворяют предикатуpred(функция, возвращающаяbool).Вместо использования
mapиfilter, рассмотрите использование макросаcollectиз модуляsugar.См. также:
- макрос sugar.collect
- шаблон filterIt
- итератор filter
- процедуру keepIf для варианта на месте
Пример:
let colors = @["red", "yellow", "black"] f1 = filter(colors, proc(x: string): bool = x.len < 6) f2 = filter(colors, proc(x: string): bool = x.contains('y')) assert f1 == @["red", "black"] assert f2 == @["yellow"]Исходный код Редактировать proc keepIf[T](s: var seq[T]; pred: proc (x: T): bool {...}{.closure.}) {...}{.inline.}
-
Сохраняет элементы из переданной последовательности
s, если они удовлетворяют предикатуpred(функция, возвращающаяbool).Обратите внимание, что
sдолжен быть объявлен какvar.Аналогично процедуре filter, но модифицирует последовательность напрямую.
См. также:
Пример:
var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1] keepIf(floats, proc(x: float): bool = x > 10) assert floats == @[13.0, 12.5, 10.1]
Исходный код Редактировать proc delete[T](s: var seq[T]; first, last: Natural)
- Удаляет элементы из последовательности
sна позицияхfirst..last(включая обе границы диапазона). Это изменяет саму последовательностьs, а не возвращает копию.Пример:
let outcome = @[1, 1, 1, 1, 1, 1, 1, 1] var dest = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] dest.delete(3, 8) assert outcome == dest
Исходный код Редактировать proc insert[T](dest: var seq[T]; src: openArray[T]; pos = 0)
-
Вставляет элементы из
srcвdestна позицииpos. Это изменяет саму последовательностьdest, а не возвращает копию.Обратите внимание, что
srcиdestдолжны быть одного типа.Пример:
var dest = @[1, 1, 1, 1, 1, 1, 1, 1] let src = @[2, 2, 2, 2, 2, 2] outcome = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] dest.insert(src, 3) assert dest == outcome
Исходный код Редактировать proc all[T](s: openArray[T]; pred: proc (x: T): bool {...}{.closure.}): bool-
Проходит по контейнеру и проверяет, удовлетворяет ли каждый элемент предикату.
См. также:
Пример:
let numbers = @[1, 4, 5, 8, 9, 7, 4] assert all(numbers, proc (x: int): bool = return x < 10) == true assert all(numbers, proc (x: int): bool = return x < 9) == false
Исходный код Редактировать proc any[T](s: openArray[T]; pred: proc (x: T): bool {...}{.closure.}): bool-
Проходит по контейнеру и проверяет, удовлетворяет ли какой-либо элемент предикату.
См. также:
Пример:
let numbers = @[1, 4, 5, 8, 9, 7, 4] assert any(numbers, proc (x: int): bool = return x > 8) == true assert any(numbers, proc (x: int): bool = return x > 9) == false
Исходный код Редактировать
Итераторы
iterator filter[T](s: openArray[T]; pred: proc (x: T): bool {...}{.closure.}): T-
Проходит по контейнеру
sи возвращает каждый элемент, удовлетворяющий предикатуpred(функция, возвращающаяbool).Вместо использования
mapиfilter, рассмотрите использование макросаcollectиз модуляsugar.См. также:
Пример:
let numbers = @[1, 4, 5, 8, 9, 7, 4] var evens = newSeq[int]() for n in filter(numbers, proc (x: int): bool = x mod 2 == 0): evens.add(n) assert evens == @[4, 8, 4]
Исходный код Редактировать iterator items[T](xs: iterator (): T): T
- итерирует по каждому элементу, возвращаемому итератором-замыканием. Это может показаться не очень полезным само по себе, но это позволяет использовать итераторы-замыкания с шаблонами mapIt, filterIt, allIt, anyIt и т.д. Исходный код Редактировать
Макросы
macro mapLiterals(constructor, op: untyped; nested = true): untyped
-
Применяет
opк каждому из атомарных литералов, таких как3или"abc"в указанномconstructorAST. Это можно использовать для отображения каждого элемента массива в некоторый целевой тип:Пример:
let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int) doAssert x is array[4, int]
Краткая запись для:
let x = [int(0.1), int(1.2), int(2.3), int(3.4)]
Если
nestedистинно (что является значением по умолчанию), литералы заменяются везде вconstructorAST, в противном случае рассматривается только первый уровень:let a = mapLiterals((1.2, (2.3, 3.4), 4.8), int) let b = mapLiterals((1.2, (2.3, 3.4), 4.8), int, nested=false) assert a == (1, (2, 3), 4) assert b == (1, (2.3, 3.4), 4) let c = mapLiterals((1, (2, 3), 4, (5, 6)), `$`) let d = mapLiterals((1, (2, 3), 4, (5, 6)), `$`, nested=false) assert c == ("1", ("2", "3"), "4", ("5", "6")) assert d == ("1", (2, 3), "4", (5, 6))Нет ограничений для
Исходный код РедактироватьconstructorAST, он работает для вложенных кортежей, массивов, множеств и т. д.
Шаблоны
template filterIt(s, pred: untyped): untyped
-
Возвращает новую последовательность со всеми элементами
s, которые удовлетворяют предикатуpred.В отличие от фильтрационного процесса и фильтрационного итератора, предикат должен быть выражением, использующим переменную
itдля проверки, например:filterIt("abcxyz", it == 'x').Вместо использования
mapItиfilterIt, рассмотрите использование макросаcollectиз модуляsugar.См. также:
Пример:
let temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44] acceptable = temperatures.filterIt(it < 50 and it > -10) notAcceptable = temperatures.filterIt(it > 50 or it < -10) assert acceptable == @[-2.0, 24.5, 44.31] assert notAcceptable == @[-272.15, 99.9, -113.44]
Исходный код Редактировать template keepItIf(varSeq: seq; pred: untyped)
-
Сохраняет элементы в переданной последовательности (должна быть объявлена как
var), если они удовлетворяют предикату.В отличие от процедуры keepIf, предикат должен быть выражением, использующим переменную
itдля проверки, например:keepItIf("abcxyz", it == 'x').См. также:
Пример:
var candidates = @["foo", "bar", "baz", "foobar"] candidates.keepItIf(it.len == 3 and it[0] == 'b') assert candidates == @["bar", "baz"]
Исходный код Редактировать template countIt(s, pred: untyped): int
-
Возвращает количество элементов, удовлетворяющих предикату.
Предикат должен быть выражением, использующим переменную
itдля проверки, например:countIt(@[1, 2, 3], it > 2).Пример:
let numbers = @[-3, -2, -1, 0, 1, 2, 3, 4, 5, 6] iterator iota(n: int): int = for i in 0..<n: yield i assert numbers.countIt(it < 0) == 3 assert countIt(iota(10), it < 2) == 2
Исходный код Редактировать template allIt(s, pred: untyped): bool
-
Итерируется по контейнеру и проверяет, удовлетворяет ли каждый элемент предикату.
В отличие от процедуры all, предикат должен быть выражением, использующим переменную
itдля проверки, например:allIt("abba", it == 'a').См. также:
Пример:
let numbers = @[1, 4, 5, 8, 9, 7, 4] assert numbers.allIt(it < 10) == true assert numbers.allIt(it < 9) == false
Исходный код Редактировать template anyIt(s, pred: untyped): bool
-
Итерируется по контейнеру и проверяет, удовлетворяет ли какой-либо элемент предикату.
В отличие от процедуры any, предикат должен быть выражением, использующим переменную
itдля проверки, например:anyIt("abba", it == 'a').См. также:
Пример:
let numbers = @[1, 4, 5, 8, 9, 7, 4] assert numbers.anyIt(it > 8) == true assert numbers.anyIt(it > 9) == false
Исходный код Редактировать template toSeq(iter: untyped): untyped
- Преобразует любой итерируемый объект (любой объект, по которому можно итерироваться, например, с помощью цикла for) в последовательность.
Пример:
let myRange = 1..5 mySet: set[int8] = {5'i8, 3, 1} assert typeof(myRange) is HSlice[system.int, system.int] assert typeof(mySet) is set[int8] let mySeq1 = toSeq(myRange) mySeq2 = toSeq(mySet) assert mySeq1 == @[1, 2, 3, 4, 5] assert mySeq2 == @[1'i8, 3, 5]Исходный код Редактировать template foldl(sequence, operation: untyped): untyped
-
Шаблон для свертки последовательности слева направо, возвращающий накопление.
Последовательность должна содержать по крайней мере один элемент. В отладочных версиях программы будет утверждение в этом случае, но в релизных версиях всё пройдёт гладко. Если последовательность содержит один элемент, он будет возвращён без применения
operation.Параметр
operationдолжен быть выражением, использующим переменныеaиbна каждом шаге свертки. Поскольку это левая свертка, для неассоциативных бинарных операций, таких как вычитание, представьте, что последовательность чисел 1, 2 и 3 будет скобоваться как (((1) - 2) - 3).См. также:
- шаблон foldl с параметром начала
- шаблон foldr
Пример:
let numbers = @[5, 9, 11] addition = foldl(numbers, a + b) subtraction = foldl(numbers, a - b) multiplication = foldl(numbers, a * b) words = @["nim", "is", "cool"] concatenation = foldl(words, a & b) procs = @["proc", "Is", "Also", "Fine"] proc foo(acc, cur: string): string = result = acc & cur assert addition == 25, "Addition is (((5)+9)+11)" assert subtraction == -15, "Subtraction is (((5)-9)-11)" assert multiplication == 495, "Multiplication is (((5)*9)*11)" assert concatenation == "nimiscool" assert foldl(procs, foo(a, b)) == "procIsAlsoFine"
Исходный код Редактировать template foldl(sequence, operation, first): untyped
-
Шаблон для свертки последовательности слева направо, возвращающий накопление.
Эта версия
foldlполучает параметр начала. Это позволяет накапливать последовательность в тип, отличный от типа элементов последовательности.Параметр
operationдолжен быть выражением, использующим переменныеaиbна каждом шаге свертки. Параметрfirst— начальное значение (первоеa) и, следовательно, определяет тип результата.См. также:
Пример:
let numbers = @[0, 8, 1, 5] digits = foldl(numbers, a & (chr(b + ord('0'))), "") assert digits == "0815"Исходный код Редактировать template foldr(sequence, operation: untyped): untyped
-
Шаблон для свертки последовательности справа налево, возвращающий накопление.
Последовательность должна содержать по крайней мере один элемент. В отладочных версиях программы будет утверждение в этом случае, но в релизных версиях всё пройдёт гладко. Если последовательность содержит один элемент, он будет возвращён без применения
operation.Параметр
operationдолжен быть выражением, использующим переменныеaиbна каждом шаге свертки. Поскольку это правая свертка, для неассоциативных бинарных операций, таких как вычитание, представьте, что последовательность чисел 1, 2 и 3 будет скобоваться как (1 - (2 - (3))).См. также:
- шаблон foldl
- шаблон foldl с параметром начала
Пример:
let numbers = @[5, 9, 11] addition = foldr(numbers, a + b) subtraction = foldr(numbers, a - b) multiplication = foldr(numbers, a * b) words = @["nim", "is", "cool"] concatenation = foldr(words, a & b) assert addition == 25, "Addition is (5+(9+(11)))" assert subtraction == 7, "Subtraction is (5-(9-(11)))" assert multiplication == 495, "Multiplication is (5*(9*(11)))" assert concatenation == "nimiscool"
Исходный код Редактировать template mapIt(s: typed; op: untyped): untyped
-
Возвращает новую последовательность с результатами применения процедуры
opк каждому элементу в контейнереs.Поскольку входные данные не изменяются, вы можете использовать его для преобразования типа элементов в входном контейнере.
Шаблон вставляет переменную
it, которую вы можете использовать непосредственно в выражении.Вместо использования
mapItиfilterIt, рассмотрите использование макросаcollectиз модуляsugar.См. также:
- макрос sugar.collect
- процедура map
- шаблон applyIt для локальной версии
Пример:
let nums = @[1, 2, 3, 4] strings = nums.mapIt($(4 * it)) assert strings == @["4", "8", "12", "16"]
Исходный код Редактировать template applyIt(varSeq, op: untyped)
-
Удобный шаблон вокруг изменяемой процедуры
applyдля сокращения набора текста.Шаблон вставляет переменную
it, которую вы можете использовать непосредственно в выражении. Выражение должно возвращать тот же тип, что и последовательность, которую вы изменяете.См. также:
Пример:
var nums = @[1, 2, 3, 4] nums.applyIt(it * 3) assert nums[0] + nums[3] == 15
Исходный код Редактировать template newSeqWith(len: int; init: untyped): untyped
-
Создаёт новую последовательность длиной
len, вызываяinitдля инициализации каждого значения последовательности.Полезно для создания "2D" последовательностей — последовательностей, содержащих другие последовательности, или для заполнения полей созданной последовательности.
Пример:
## Creates a sequence containing 5 bool sequences, each of length of 3. var seq2D = newSeqWith(5, newSeq[bool](3)) assert seq2D.len == 5 assert seq2D[0].len == 3 assert seq2D[4][2] == false ## Creates a sequence of 20 random numbers from 1 to 10 import random var seqRand = newSeqWith(20, rand(10))
Исходный код Редактировать
© 2006–2021 Andreas Rumpf
Licensed under the MIT License.
https://nim-lang.org/docs/sequtils.html