sequtils.nim 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2011 Alexander Mitchell-Robinson
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## :Author: Alexander Mitchell-Robinson (Amrykid)
  10. ##
  11. ## This module implements operations for the built-in `seq`:idx: type which
  12. ## were inspired by functional programming languages.
  13. ##
  14. ## For functional style programming you may want to pass `anonymous procs
  15. ## <manual.html#procedures-anonymous-procs>`_ to procs like ``filter`` to
  16. ## reduce typing. Anonymous procs can use `the special do notation
  17. ## <manual.html#procedures-do-notation>`_
  18. ## which is more convenient in certain situations.
  19. include "system/inclrtl"
  20. import macros
  21. when not defined(nimhygiene):
  22. {.pragma: dirty.}
  23. macro evalOnceAs(expAlias, exp: untyped, letAssigneable: static[bool]): untyped =
  24. ## Injects ``expAlias`` in caller scope, to avoid bugs involving multiple
  25. ## substitution in macro arguments such as
  26. ## https://github.com/nim-lang/Nim/issues/7187
  27. ## ``evalOnceAs(myAlias, myExp)`` will behave as ``let myAlias = myExp``
  28. ## except when ``letAssigneable`` is false (eg to handle openArray) where
  29. ## it just forwards ``exp`` unchanged
  30. expectKind(expAlias, nnkIdent)
  31. var val = exp
  32. result = newStmtList()
  33. # If `exp` is not a symbol we evaluate it once here and then use the temporary
  34. # symbol as alias
  35. if exp.kind != nnkSym and letAssigneable:
  36. val = genSym()
  37. result.add(newLetStmt(val, exp))
  38. result.add(
  39. newProc(name = genSym(nskTemplate, $expAlias), params = [getType(untyped)],
  40. body = val, procType = nnkTemplateDef))
  41. proc concat*[T](seqs: varargs[seq[T]]): seq[T] =
  42. ## Takes several sequences' items and returns them inside a new sequence.
  43. ##
  44. ## Example:
  45. ##
  46. ## .. code-block::
  47. ## let
  48. ## s1 = @[1, 2, 3]
  49. ## s2 = @[4, 5]
  50. ## s3 = @[6, 7]
  51. ## total = concat(s1, s2, s3)
  52. ## assert total == @[1, 2, 3, 4, 5, 6, 7]
  53. var L = 0
  54. for seqitm in items(seqs): inc(L, len(seqitm))
  55. newSeq(result, L)
  56. var i = 0
  57. for s in items(seqs):
  58. for itm in items(s):
  59. result[i] = itm
  60. inc(i)
  61. proc count*[T](s: openArray[T], x: T): int =
  62. ## Returns the number of occurrences of the item `x` in the container `s`.
  63. ##
  64. ## Example:
  65. ##
  66. ## .. code-block::
  67. ## let
  68. ## s = @[1, 2, 2, 3, 2, 4, 2]
  69. ## c = count(s, 2)
  70. ## assert c == 4
  71. for itm in items(s):
  72. if itm == x:
  73. inc result
  74. proc cycle*[T](s: openArray[T], n: Natural): seq[T] =
  75. ## Returns a new sequence with the items of the container `s` repeated
  76. ## `n` times.
  77. ##
  78. ## Example:
  79. ##
  80. ## .. code-block::
  81. ##
  82. ## let
  83. ## s = @[1, 2, 3]
  84. ## total = s.cycle(3)
  85. ## assert total == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
  86. result = newSeq[T](n * s.len)
  87. var o = 0
  88. for x in 0 ..< n:
  89. for e in s:
  90. result[o] = e
  91. inc o
  92. proc repeat*[T](x: T, n: Natural): seq[T] =
  93. ## Returns a new sequence with the item `x` repeated `n` times.
  94. ##
  95. ## Example:
  96. ##
  97. ## .. code-block::
  98. ##
  99. ## let
  100. ## total = repeat(5, 3)
  101. ## assert total == @[5, 5, 5]
  102. result = newSeq[T](n)
  103. for i in 0 ..< n:
  104. result[i] = x
  105. proc deduplicate*[T](s: openArray[T]): seq[T] =
  106. ## Returns a new sequence without duplicates.
  107. ##
  108. ## Example:
  109. ##
  110. ## .. code-block::
  111. ## let
  112. ## dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
  113. ## dup2 = @["a", "a", "c", "d", "d"]
  114. ## unique1 = deduplicate(dup1)
  115. ## unique2 = deduplicate(dup2)
  116. ## assert unique1 == @[1, 3, 4, 2, 8]
  117. ## assert unique2 == @["a", "c", "d"]
  118. result = @[]
  119. for itm in items(s):
  120. if not result.contains(itm): result.add(itm)
  121. proc zip*[S, T](s1: openArray[S], s2: openArray[T]): seq[tuple[a: S, b: T]] =
  122. ## Returns a new sequence with a combination of the two input containers.
  123. ##
  124. ## For convenience you can access the returned tuples through the named
  125. ## fields `a` and `b`. If one container is shorter, the remaining items in
  126. ## the longer container are discarded.
  127. ##
  128. ## Example:
  129. ##
  130. ## .. code-block::
  131. ## let
  132. ## short = @[1, 2, 3]
  133. ## long = @[6, 5, 4, 3, 2, 1]
  134. ## words = @["one", "two", "three"]
  135. ## zip1 = zip(short, long)
  136. ## zip2 = zip(short, words)
  137. ## assert zip1 == @[(1, 6), (2, 5), (3, 4)]
  138. ## assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
  139. ## assert zip1[2].b == 4
  140. ## assert zip2[2].b == "three"
  141. var m = min(s1.len, s2.len)
  142. newSeq(result, m)
  143. for i in 0 ..< m:
  144. result[i] = (s1[i], s2[i])
  145. proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] =
  146. ## Splits and distributes a sequence `s` into `num` sub sequences.
  147. ##
  148. ## Returns a sequence of `num` sequences. For some input values this is the
  149. ## inverse of the `concat <#concat>`_ proc. The proc will assert in debug
  150. ## builds if `s` is nil or `num` is less than one, and will likely crash on
  151. ## release builds. The input sequence `s` can be empty, which will produce
  152. ## `num` empty sequences.
  153. ##
  154. ## If `spread` is false and the length of `s` is not a multiple of `num`, the
  155. ## proc will max out the first sub sequences with ``1 + len(s) div num``
  156. ## entries, leaving the remainder of elements to the last sequence.
  157. ##
  158. ## On the other hand, if `spread` is true, the proc will distribute evenly
  159. ## the remainder of the division across all sequences, which makes the result
  160. ## more suited to multithreading where you are passing equal sized work units
  161. ## to a thread pool and want to maximize core usage.
  162. ##
  163. ## Example:
  164. ##
  165. ## .. code-block::
  166. ## let numbers = @[1, 2, 3, 4, 5, 6, 7]
  167. ## assert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
  168. ## assert numbers.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
  169. ## assert numbers.distribute(6)[0] == @[1, 2]
  170. ## assert numbers.distribute(6)[5] == @[7]
  171. if num < 2:
  172. result = @[s]
  173. return
  174. let num = int(num) # XXX probably only needed because of .. bug
  175. # Create the result and calculate the stride size and the remainder if any.
  176. result = newSeq[seq[T]](num)
  177. var
  178. stride = s.len div num
  179. first = 0
  180. last = 0
  181. extra = s.len mod num
  182. if extra == 0 or spread == false:
  183. # Use an algorithm which overcounts the stride and minimizes reading limits.
  184. if extra > 0: inc(stride)
  185. for i in 0 ..< num:
  186. result[i] = newSeq[T]()
  187. for g in first ..< min(s.len, first + stride):
  188. result[i].add(s[g])
  189. first += stride
  190. else:
  191. # Use an undercounting algorithm which *adds* the remainder each iteration.
  192. for i in 0 ..< num:
  193. last = first + stride
  194. if extra > 0:
  195. extra -= 1
  196. inc(last)
  197. result[i] = newSeq[T]()
  198. for g in first ..< last:
  199. result[i].add(s[g])
  200. first = last
  201. proc map*[T, S](s: openArray[T], op: proc (x: T): S {.closure.}):
  202. seq[S]{.inline.} =
  203. ## Returns a new sequence with the results of `op` applied to every item in
  204. ## the container `s`.
  205. ##
  206. ## Since the input is not modified you can use this version of ``map`` to
  207. ## transform the type of the elements in the input container.
  208. ##
  209. ## Example:
  210. ##
  211. ## .. code-block:: nim
  212. ## let
  213. ## a = @[1, 2, 3, 4]
  214. ## b = map(a, proc(x: int): string = $x)
  215. ## assert b == @["1", "2", "3", "4"]
  216. newSeq(result, s.len)
  217. for i in 0 ..< s.len:
  218. result[i] = op(s[i])
  219. proc map*[T](s: var openArray[T], op: proc (x: var T) {.closure.})
  220. {.deprecated.} =
  221. ## Applies `op` to every item in `s` modifying it directly.
  222. ##
  223. ## Note that this version of ``map`` requires your input and output types to
  224. ## be the same, since they are modified in-place.
  225. ##
  226. ## Example:
  227. ##
  228. ## .. code-block:: nim
  229. ## var a = @["1", "2", "3", "4"]
  230. ## echo repr(a)
  231. ## # --> ["1", "2", "3", "4"]
  232. ## map(a, proc(x: var string) = x &= "42")
  233. ## echo repr(a)
  234. ## # --> ["142", "242", "342", "442"]
  235. ## **Deprecated since version 0.12.0:** Use the ``apply`` proc instead.
  236. for i in 0 ..< s.len: op(s[i])
  237. proc apply*[T](s: var openArray[T], op: proc (x: var T) {.closure.})
  238. {.inline.} =
  239. ## Applies `op` to every item in `s` modifying it directly.
  240. ##
  241. ## Note that this requires your input and output types to
  242. ## be the same, since they are modified in-place.
  243. ## The parameter function takes a ``var T`` type parameter.
  244. ##
  245. ## Example:
  246. ##
  247. ## .. code-block:: nim
  248. ## var a = @["1", "2", "3", "4"]
  249. ## echo repr(a)
  250. ## # --> ["1", "2", "3", "4"]
  251. ## apply(a, proc(x: var string) = x &= "42")
  252. ## echo repr(a)
  253. ## # --> ["142", "242", "342", "442"]
  254. ##
  255. for i in 0 ..< s.len: op(s[i])
  256. proc apply*[T](s: var openArray[T], op: proc (x: T): T {.closure.})
  257. {.inline.} =
  258. ## Applies `op` to every item in `s` modifying it directly.
  259. ##
  260. ## Note that this requires your input and output types to
  261. ## be the same, since they are modified in-place.
  262. ## The parameter function takes and returns a ``T`` type variable.
  263. ##
  264. ## Example:
  265. ##
  266. ## .. code-block:: nim
  267. ## var a = @["1", "2", "3", "4"]
  268. ## echo repr(a)
  269. ## # --> ["1", "2", "3", "4"]
  270. ## apply(a, proc(x: string): string = x & "42")
  271. ## echo repr(a)
  272. ## # --> ["142", "242", "342", "442"]
  273. ##
  274. for i in 0 ..< s.len: s[i] = op(s[i])
  275. iterator filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): T =
  276. ## Iterates through a container and yields every item that fulfills the
  277. ## predicate.
  278. ##
  279. ## Example:
  280. ##
  281. ## .. code-block::
  282. ## let numbers = @[1, 4, 5, 8, 9, 7, 4]
  283. ## for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
  284. ## echo($n)
  285. ## # echoes 4, 8, 4 in separate lines
  286. for i in 0 ..< s.len:
  287. if pred(s[i]):
  288. yield s[i]
  289. proc filter*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): seq[T]
  290. {.inline.} =
  291. ## Returns a new sequence with all the items that fulfilled the predicate.
  292. ##
  293. ## Example:
  294. ##
  295. ## .. code-block::
  296. ## let
  297. ## colors = @["red", "yellow", "black"]
  298. ## f1 = filter(colors, proc(x: string): bool = x.len < 6)
  299. ## f2 = filter(colors) do (x: string) -> bool : x.len > 5
  300. ## assert f1 == @["red", "black"]
  301. ## assert f2 == @["yellow"]
  302. result = newSeq[T]()
  303. for i in 0 ..< s.len:
  304. if pred(s[i]):
  305. result.add(s[i])
  306. proc keepIf*[T](s: var seq[T], pred: proc(x: T): bool {.closure.})
  307. {.inline.} =
  308. ## Keeps the items in the passed sequence if they fulfilled the predicate.
  309. ## Same as the ``filter`` proc, but modifies the sequence directly.
  310. ##
  311. ## Example:
  312. ##
  313. ## .. code-block::
  314. ## var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
  315. ## keepIf(floats, proc(x: float): bool = x > 10)
  316. ## assert floats == @[13.0, 12.5, 10.1]
  317. var pos = 0
  318. for i in 0 ..< len(s):
  319. if pred(s[i]):
  320. if pos != i:
  321. shallowCopy(s[pos], s[i])
  322. inc(pos)
  323. setLen(s, pos)
  324. proc delete*[T](s: var seq[T]; first, last: Natural) =
  325. ## Deletes in `s` the items at position `first` .. `last`. This modifies
  326. ## `s` itself, it does not return a copy.
  327. ##
  328. ## Example:
  329. ##
  330. ##.. code-block::
  331. ## let outcome = @[1,1,1,1,1,1,1,1]
  332. ## var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
  333. ## dest.delete(3, 8)
  334. ## assert outcome == dest
  335. var i = first
  336. var j = last+1
  337. var newLen = len(s)-j+i
  338. while i < newLen:
  339. s[i].shallowCopy(s[j])
  340. inc(i)
  341. inc(j)
  342. setLen(s, newLen)
  343. proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
  344. ## Inserts items from `src` into `dest` at position `pos`. This modifies
  345. ## `dest` itself, it does not return a copy.
  346. ##
  347. ## Example:
  348. ##
  349. ##.. code-block::
  350. ## var dest = @[1,1,1,1,1,1,1,1]
  351. ## let
  352. ## src = @[2,2,2,2,2,2]
  353. ## outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
  354. ## dest.insert(src, 3)
  355. ## assert dest == outcome
  356. var j = len(dest) - 1
  357. var i = len(dest) + len(src) - 1
  358. dest.setLen(i + 1)
  359. # Move items after `pos` to the end of the sequence.
  360. while j >= pos:
  361. dest[i].shallowCopy(dest[j])
  362. dec(i)
  363. dec(j)
  364. # Insert items from `dest` into `dest` at `pos`
  365. inc(j)
  366. for item in src:
  367. dest[j] = item
  368. inc(j)
  369. template filterIt*(s, pred: untyped): untyped =
  370. ## Returns a new sequence with all the items that fulfilled the predicate.
  371. ##
  372. ## Unlike the `proc` version, the predicate needs to be an expression using
  373. ## the ``it`` variable for testing, like: ``filterIt("abcxyz", it == 'x')``.
  374. ##
  375. ## Example:
  376. ##
  377. ## .. code-block::
  378. ## let
  379. ## temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
  380. ## acceptable = filterIt(temperatures, it < 50 and it > -10)
  381. ## notAcceptable = filterIt(temperatures, it > 50 or it < -10)
  382. ## assert acceptable == @[-2.0, 24.5, 44.31]
  383. ## assert notAcceptable == @[-272.15, 99.9, -113.44]
  384. var result = newSeq[type(s[0])]()
  385. for it {.inject.} in items(s):
  386. if pred: result.add(it)
  387. result
  388. template keepItIf*(varSeq: seq, pred: untyped) =
  389. ## Convenience template around the ``keepIf`` proc to reduce typing.
  390. ##
  391. ## Unlike the `proc` version, the predicate needs to be an expression using
  392. ## the ``it`` variable for testing, like: ``keepItIf("abcxyz", it == 'x')``.
  393. ##
  394. ## Example:
  395. ##
  396. ## .. code-block::
  397. ## var candidates = @["foo", "bar", "baz", "foobar"]
  398. ## keepItIf(candidates, it.len == 3 and it[0] == 'b')
  399. ## assert candidates == @["bar", "baz"]
  400. var pos = 0
  401. for i in 0 ..< len(varSeq):
  402. let it {.inject.} = varSeq[i]
  403. if pred:
  404. if pos != i:
  405. shallowCopy(varSeq[pos], varSeq[i])
  406. inc(pos)
  407. setLen(varSeq, pos)
  408. proc all*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool =
  409. ## Iterates through a container and checks if every item fulfills the
  410. ## predicate.
  411. ##
  412. ## Example:
  413. ##
  414. ## .. code-block::
  415. ## let numbers = @[1, 4, 5, 8, 9, 7, 4]
  416. ## assert all(numbers, proc (x: int): bool = return x < 10) == true
  417. ## assert all(numbers, proc (x: int): bool = return x < 9) == false
  418. for i in s:
  419. if not pred(i):
  420. return false
  421. return true
  422. template allIt*(s, pred: untyped): bool =
  423. ## Checks if every item fulfills the predicate.
  424. ##
  425. ## Example:
  426. ##
  427. ## .. code-block::
  428. ## let numbers = @[1, 4, 5, 8, 9, 7, 4]
  429. ## assert allIt(numbers, it < 10) == true
  430. ## assert allIt(numbers, it < 9) == false
  431. var result = true
  432. for it {.inject.} in items(s):
  433. if not pred:
  434. result = false
  435. break
  436. result
  437. proc any*[T](s: openArray[T], pred: proc(x: T): bool {.closure.}): bool =
  438. ## Iterates through a container and checks if some item fulfills the
  439. ## predicate.
  440. ##
  441. ## Example:
  442. ##
  443. ## .. code-block::
  444. ## let numbers = @[1, 4, 5, 8, 9, 7, 4]
  445. ## assert any(numbers, proc (x: int): bool = return x > 8) == true
  446. ## assert any(numbers, proc (x: int): bool = return x > 9) == false
  447. for i in s:
  448. if pred(i):
  449. return true
  450. return false
  451. template anyIt*(s, pred: untyped): bool =
  452. ## Checks if some item fulfills the predicate.
  453. ##
  454. ## Example:
  455. ##
  456. ## .. code-block::
  457. ## let numbers = @[1, 4, 5, 8, 9, 7, 4]
  458. ## assert anyIt(numbers, it > 8) == true
  459. ## assert anyIt(numbers, it > 9) == false
  460. var result = false
  461. for it {.inject.} in items(s):
  462. if pred:
  463. result = true
  464. break
  465. result
  466. template toSeq*(iter: untyped): untyped =
  467. ## Transforms any iterator into a sequence.
  468. ##
  469. ## Example:
  470. ##
  471. ## .. code-block::
  472. ## let
  473. ## numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
  474. ## odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
  475. ## if x mod 2 == 1:
  476. ## result = true)
  477. ## assert odd_numbers == @[1, 3, 5, 7, 9]
  478. # Note: see also `mapIt` for explanation of some of the implementation
  479. # subtleties.
  480. when compiles(iter.len):
  481. block:
  482. evalOnceAs(iter2, iter, true)
  483. var result = newSeq[type(iter)](iter2.len)
  484. var i = 0
  485. for x in iter2:
  486. result[i] = x
  487. inc i
  488. result
  489. else:
  490. var result: seq[type(iter)] = @[]
  491. for x in iter:
  492. result.add(x)
  493. result
  494. template foldl*(sequence, operation: untyped): untyped =
  495. ## Template to fold a sequence from left to right, returning the accumulation.
  496. ##
  497. ## The sequence is required to have at least a single element. Debug versions
  498. ## of your program will assert in this situation but release versions will
  499. ## happily go ahead. If the sequence has a single element it will be returned
  500. ## without applying ``operation``.
  501. ##
  502. ## The ``operation`` parameter should be an expression which uses the
  503. ## variables ``a`` and ``b`` for each step of the fold. Since this is a left
  504. ## fold, for non associative binary operations like subtraction think that
  505. ## the sequence of numbers 1, 2 and 3 will be parenthesized as (((1) - 2) -
  506. ## 3).
  507. ##
  508. ## Example:
  509. ##
  510. ## .. code-block::
  511. ## let
  512. ## numbers = @[5, 9, 11]
  513. ## addition = foldl(numbers, a + b)
  514. ## subtraction = foldl(numbers, a - b)
  515. ## multiplication = foldl(numbers, a * b)
  516. ## words = @["nim", "is", "cool"]
  517. ## concatenation = foldl(words, a & b)
  518. ## assert addition == 25, "Addition is (((5)+9)+11)"
  519. ## assert subtraction == -15, "Subtraction is (((5)-9)-11)"
  520. ## assert multiplication == 495, "Multiplication is (((5)*9)*11)"
  521. ## assert concatenation == "nimiscool"
  522. let s = sequence
  523. assert s.len > 0, "Can't fold empty sequences"
  524. var result: type(s[0])
  525. result = s[0]
  526. for i in 1..<s.len:
  527. let
  528. a {.inject.} = result
  529. b {.inject.} = s[i]
  530. result = operation
  531. result
  532. template foldl*(sequence, operation, first): untyped =
  533. ## Template to fold a sequence from left to right, returning the accumulation.
  534. ##
  535. ## This version of ``foldl`` gets a starting parameter. This makes it possible
  536. ## to accumulate the sequence into a different type than the sequence elements.
  537. ##
  538. ## The ``operation`` parameter should be an expression which uses the variables
  539. ## ``a`` and ``b`` for each step of the fold. The ``first`` parameter is the
  540. ## start value (the first ``a``) and therefor defines the type of the result.
  541. ##
  542. ## Example:
  543. ##
  544. ## .. code-block::
  545. ## let
  546. ## numbers = @[0, 8, 1, 5]
  547. ## digits = foldl(numbers, a & (chr(b + ord('0'))), "")
  548. ## assert digits == "0815"
  549. var result: type(first)
  550. result = first
  551. for x in items(sequence):
  552. let
  553. a {.inject.} = result
  554. b {.inject.} = x
  555. result = operation
  556. result
  557. template foldr*(sequence, operation: untyped): untyped =
  558. ## Template to fold a sequence from right to left, returning the accumulation.
  559. ##
  560. ## The sequence is required to have at least a single element. Debug versions
  561. ## of your program will assert in this situation but release versions will
  562. ## happily go ahead. If the sequence has a single element it will be returned
  563. ## without applying ``operation``.
  564. ##
  565. ## The ``operation`` parameter should be an expression which uses the
  566. ## variables ``a`` and ``b`` for each step of the fold. Since this is a right
  567. ## fold, for non associative binary operations like subtraction think that
  568. ## the sequence of numbers 1, 2 and 3 will be parenthesized as (1 - (2 -
  569. ## (3))).
  570. ##
  571. ## Example:
  572. ##
  573. ## .. code-block::
  574. ## let
  575. ## numbers = @[5, 9, 11]
  576. ## addition = foldr(numbers, a + b)
  577. ## subtraction = foldr(numbers, a - b)
  578. ## multiplication = foldr(numbers, a * b)
  579. ## words = @["nim", "is", "cool"]
  580. ## concatenation = foldr(words, a & b)
  581. ## assert addition == 25, "Addition is (5+(9+(11)))"
  582. ## assert subtraction == 7, "Subtraction is (5-(9-(11)))"
  583. ## assert multiplication == 495, "Multiplication is (5*(9*(11)))"
  584. ## assert concatenation == "nimiscool"
  585. let s = sequence
  586. assert s.len > 0, "Can't fold empty sequences"
  587. var result: type(s[0])
  588. result = sequence[s.len - 1]
  589. for i in countdown(s.len - 2, 0):
  590. let
  591. a {.inject.} = s[i]
  592. b {.inject.} = result
  593. result = operation
  594. result
  595. template mapIt*(s, typ, op: untyped): untyped =
  596. ## Convenience template around the ``map`` proc to reduce typing.
  597. ##
  598. ## The template injects the ``it`` variable which you can use directly in an
  599. ## expression. You also need to pass as `typ` the type of the expression,
  600. ## since the new returned sequence can have a different type than the
  601. ## original.
  602. ##
  603. ## Example:
  604. ##
  605. ## .. code-block::
  606. ## let
  607. ## nums = @[1, 2, 3, 4]
  608. ## strings = nums.mapIt(string, $(4 * it))
  609. ## assert strings == @["4", "8", "12", "16"]
  610. ## **Deprecated since version 0.12.0:** Use the ``mapIt(seq1, op)``
  611. ## template instead.
  612. var result: seq[typ] = @[]
  613. for it {.inject.} in items(s):
  614. result.add(op)
  615. result
  616. template mapIt*(s: typed, op: untyped): untyped =
  617. ## Convenience template around the ``map`` proc to reduce typing.
  618. ##
  619. ## The template injects the ``it`` variable which you can use directly in an
  620. ## expression.
  621. ##
  622. ## Example:
  623. ##
  624. ## .. code-block::
  625. ## let
  626. ## nums = @[1, 2, 3, 4]
  627. ## strings = nums.mapIt($(4 * it))
  628. ## assert strings == @["4", "8", "12", "16"]
  629. when defined(nimHasTypeof):
  630. type outType = typeof((
  631. block:
  632. var it{.inject.}: typeof(items(s), typeOfIter);
  633. op), typeOfProc)
  634. else:
  635. type outType = type((
  636. block:
  637. var it{.inject.}: type(items(s));
  638. op))
  639. when compiles(s.len):
  640. block: # using a block avoids https://github.com/nim-lang/Nim/issues/8580
  641. # BUG: `evalOnceAs(s2, s, false)` would lead to C compile errors
  642. # (`error: use of undeclared identifier`) instead of Nim compile errors
  643. evalOnceAs(s2, s, compiles((let _ = s)))
  644. var i = 0
  645. var result = newSeq[outType](s2.len)
  646. for it {.inject.} in s2:
  647. result[i] = op
  648. i += 1
  649. result
  650. else:
  651. var result: seq[outType] = @[]
  652. for it {.inject.} in s:
  653. result.add(op)
  654. result
  655. template applyIt*(varSeq, op: untyped) =
  656. ## Convenience template around the mutable ``apply`` proc to reduce typing.
  657. ##
  658. ## The template injects the ``it`` variable which you can use directly in an
  659. ## expression. The expression has to return the same type as the sequence you
  660. ## are mutating.
  661. ##
  662. ## Example:
  663. ##
  664. ## .. code-block::
  665. ## var nums = @[1, 2, 3, 4]
  666. ## nums.applyIt(it * 3)
  667. ## assert nums[0] + nums[3] == 15
  668. for i in low(varSeq) .. high(varSeq):
  669. let it {.inject.} = varSeq[i]
  670. varSeq[i] = op
  671. template newSeqWith*(len: int, init: untyped): untyped =
  672. ## creates a new sequence, calling `init` to initialize each value.
  673. ##
  674. ## Example:
  675. ##
  676. ## .. code-block::
  677. ## var seq2D = newSeqWith(20, newSeq[bool](10))
  678. ## seq2D[0][0] = true
  679. ## seq2D[1][0] = true
  680. ## seq2D[0][1] = true
  681. ##
  682. ## import random
  683. ## var seqRand = newSeqWith(20, random(10))
  684. ## echo seqRand
  685. var result = newSeq[type(init)](len)
  686. for i in 0 ..< len:
  687. result[i] = init
  688. result
  689. proc mapLitsImpl(constructor: NimNode; op: NimNode; nested: bool;
  690. filter = nnkLiterals): NimNode =
  691. if constructor.kind in filter:
  692. result = newNimNode(nnkCall, lineInfoFrom=constructor)
  693. result.add op
  694. result.add constructor
  695. else:
  696. result = copyNimNode(constructor)
  697. for v in constructor:
  698. if nested or v.kind in filter:
  699. result.add mapLitsImpl(v, op, nested, filter)
  700. else:
  701. result.add v
  702. macro mapLiterals*(constructor, op: untyped;
  703. nested = true): untyped =
  704. ## applies ``op`` to each of the **atomic** literals like ``3``
  705. ## or ``"abc"`` in the specified ``constructor`` AST. This can
  706. ## be used to map every array element to some target type:
  707. ##
  708. ## Example:
  709. ##
  710. ## .. code-block::
  711. ## let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int)
  712. ## doAssert x is array[4, int]
  713. ##
  714. ## Short notation for:
  715. ##
  716. ## .. code-block::
  717. ## let x = [int(0.1), int(1.2), int(2.3), int(3.4)]
  718. ##
  719. ## If ``nested`` is true, the literals are replaced everywhere
  720. ## in the ``constructor`` AST, otherwise only the first level
  721. ## is considered:
  722. ##
  723. ## .. code-block::
  724. ## mapLiterals((1, ("abc"), 2), float, nested=false)
  725. ##
  726. ## Produces::
  727. ##
  728. ## (float(1), ("abc"), float(2))
  729. ##
  730. ## There are no constraints for the ``constructor`` AST, it
  731. ## works for nested tuples of arrays of sets etc.
  732. result = mapLitsImpl(constructor, op, nested.boolVal)
  733. when isMainModule:
  734. import strutils
  735. # helper for testing double substitution side effects which are handled
  736. # by `evalOnceAs`
  737. var counter = 0
  738. proc identity[T](a:T):auto=
  739. counter.inc
  740. a
  741. block: # concat test
  742. let
  743. s1 = @[1, 2, 3]
  744. s2 = @[4, 5]
  745. s3 = @[6, 7]
  746. total = concat(s1, s2, s3)
  747. assert total == @[1, 2, 3, 4, 5, 6, 7]
  748. block: # count test
  749. let
  750. s1 = @[1, 2, 3, 2]
  751. s2 = @['a', 'b', 'x', 'a']
  752. a1 = [1, 2, 3, 2]
  753. a2 = ['a', 'b', 'x', 'a']
  754. r0 = count(s1, 0)
  755. r1 = count(s1, 1)
  756. r2 = count(s1, 2)
  757. r3 = count(s2, 'y')
  758. r4 = count(s2, 'x')
  759. r5 = count(s2, 'a')
  760. ar0 = count(a1, 0)
  761. ar1 = count(a1, 1)
  762. ar2 = count(a1, 2)
  763. ar3 = count(a2, 'y')
  764. ar4 = count(a2, 'x')
  765. ar5 = count(a2, 'a')
  766. assert r0 == 0
  767. assert r1 == 1
  768. assert r2 == 2
  769. assert r3 == 0
  770. assert r4 == 1
  771. assert r5 == 2
  772. assert ar0 == 0
  773. assert ar1 == 1
  774. assert ar2 == 2
  775. assert ar3 == 0
  776. assert ar4 == 1
  777. assert ar5 == 2
  778. block: # cycle tests
  779. let
  780. a = @[1, 2, 3]
  781. b: seq[int] = @[]
  782. c = [1, 2, 3]
  783. doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
  784. doAssert a.cycle(0) == @[]
  785. #doAssert a.cycle(-1) == @[] # will not compile!
  786. doAssert b.cycle(3) == @[]
  787. doAssert c.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
  788. doAssert c.cycle(0) == @[]
  789. block: # repeat tests
  790. assert repeat(10, 5) == @[10, 10, 10, 10, 10]
  791. assert repeat(@[1,2,3], 2) == @[@[1,2,3], @[1,2,3]]
  792. assert repeat([1,2,3], 2) == @[[1,2,3], [1,2,3]]
  793. block: # deduplicates test
  794. let
  795. dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
  796. dup2 = @["a", "a", "c", "d", "d"]
  797. dup3 = [1, 1, 3, 4, 2, 2, 8, 1, 4]
  798. dup4 = ["a", "a", "c", "d", "d"]
  799. unique1 = deduplicate(dup1)
  800. unique2 = deduplicate(dup2)
  801. unique3 = deduplicate(dup3)
  802. unique4 = deduplicate(dup4)
  803. assert unique1 == @[1, 3, 4, 2, 8]
  804. assert unique2 == @["a", "c", "d"]
  805. assert unique3 == @[1, 3, 4, 2, 8]
  806. assert unique4 == @["a", "c", "d"]
  807. block: # zip test
  808. let
  809. short = @[1, 2, 3]
  810. long = @[6, 5, 4, 3, 2, 1]
  811. words = @["one", "two", "three"]
  812. ashort = [1, 2, 3]
  813. along = [6, 5, 4, 3, 2, 1]
  814. awords = ["one", "two", "three"]
  815. zip1 = zip(short, long)
  816. zip2 = zip(short, words)
  817. zip3 = zip(ashort, along)
  818. zip4 = zip(ashort, awords)
  819. zip5 = zip(ashort, words)
  820. assert zip1 == @[(1, 6), (2, 5), (3, 4)]
  821. assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
  822. assert zip3 == @[(1, 6), (2, 5), (3, 4)]
  823. assert zip4 == @[(1, "one"), (2, "two"), (3, "three")]
  824. assert zip5 == @[(1, "one"), (2, "two"), (3, "three")]
  825. assert zip1[2].b == 4
  826. assert zip2[2].b == "three"
  827. assert zip3[2].b == 4
  828. assert zip4[2].b == "three"
  829. assert zip5[2].b == "three"
  830. block: # distribute tests
  831. let numbers = @[1, 2, 3, 4, 5, 6, 7]
  832. doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
  833. doAssert numbers.distribute(6)[0] == @[1, 2]
  834. doAssert numbers.distribute(6)[5] == @[7]
  835. let a = @[1, 2, 3, 4, 5, 6, 7]
  836. doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]]
  837. doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]]
  838. doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]]
  839. doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]]
  840. doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
  841. doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
  842. doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
  843. doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
  844. doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]]
  845. doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]]
  846. doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]]
  847. doAssert a.distribute(6, false) == @[
  848. @[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]]
  849. doAssert a.distribute(8, false) == a.distribute(8, true)
  850. doAssert a.distribute(90, false) == a.distribute(90, true)
  851. var b = @[0]
  852. for f in 1 .. 25: b.add(f)
  853. doAssert b.distribute(5, true)[4].len == 5
  854. doAssert b.distribute(5, false)[4].len == 2
  855. block: # map test
  856. let
  857. numbers = @[1, 4, 5, 8, 9, 7, 4]
  858. anumbers = [1, 4, 5, 8, 9, 7, 4]
  859. m1 = map(numbers, proc(x: int): int = 2*x)
  860. m2 = map(anumbers, proc(x: int): int = 2*x)
  861. assert m1 == @[2, 8, 10, 16, 18, 14, 8]
  862. assert m2 == @[2, 8, 10, 16, 18, 14, 8]
  863. block: # apply test
  864. var a = @["1", "2", "3", "4"]
  865. apply(a, proc(x: var string) = x &= "42")
  866. assert a == @["142", "242", "342", "442"]
  867. block: # filter proc test
  868. let
  869. colors = @["red", "yellow", "black"]
  870. acolors = ["red", "yellow", "black"]
  871. f1 = filter(colors, proc(x: string): bool = x.len < 6)
  872. f2 = filter(colors) do (x: string) -> bool : x.len > 5
  873. f3 = filter(acolors, proc(x: string): bool = x.len < 6)
  874. f4 = filter(acolors) do (x: string) -> bool : x.len > 5
  875. assert f1 == @["red", "black"]
  876. assert f2 == @["yellow"]
  877. assert f3 == @["red", "black"]
  878. assert f4 == @["yellow"]
  879. block: # filter iterator test
  880. let numbers = @[1, 4, 5, 8, 9, 7, 4]
  881. let anumbers = [1, 4, 5, 8, 9, 7, 4]
  882. assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
  883. @[4, 8, 4]
  884. assert toSeq(filter(anumbers, proc (x: int): bool = x mod 2 == 0)) ==
  885. @[4, 8, 4]
  886. block: # keepIf test
  887. var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
  888. keepIf(floats, proc(x: float): bool = x > 10)
  889. assert floats == @[13.0, 12.5, 10.1]
  890. block: # delete tests
  891. let outcome = @[1,1,1,1,1,1,1,1]
  892. var dest = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
  893. dest.delete(3, 8)
  894. assert outcome == dest, """\
  895. Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
  896. is [1,1,1,1,1,1,1,1]"""
  897. block: # insert tests
  898. var dest = @[1,1,1,1,1,1,1,1]
  899. let
  900. src = @[2,2,2,2,2,2]
  901. outcome = @[1,1,1,2,2,2,2,2,2,1,1,1,1,1]
  902. dest.insert(src, 3)
  903. assert dest == outcome, """\
  904. Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
  905. at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
  906. block: # filterIt test
  907. let
  908. temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
  909. acceptable = filterIt(temperatures, it < 50 and it > -10)
  910. notAcceptable = filterIt(temperatures, it > 50 or it < -10)
  911. assert acceptable == @[-2.0, 24.5, 44.31]
  912. assert notAcceptable == @[-272.15, 99.9, -113.44]
  913. block: # keepItIf test
  914. var candidates = @["foo", "bar", "baz", "foobar"]
  915. keepItIf(candidates, it.len == 3 and it[0] == 'b')
  916. assert candidates == @["bar", "baz"]
  917. block: # all
  918. let
  919. numbers = @[1, 4, 5, 8, 9, 7, 4]
  920. anumbers = [1, 4, 5, 8, 9, 7, 4]
  921. len0seq : seq[int] = @[]
  922. assert all(numbers, proc (x: int): bool = return x < 10) == true
  923. assert all(numbers, proc (x: int): bool = return x < 9) == false
  924. assert all(len0seq, proc (x: int): bool = return false) == true
  925. assert all(anumbers, proc (x: int): bool = return x < 10) == true
  926. assert all(anumbers, proc (x: int): bool = return x < 9) == false
  927. block: # allIt
  928. let
  929. numbers = @[1, 4, 5, 8, 9, 7, 4]
  930. anumbers = [1, 4, 5, 8, 9, 7, 4]
  931. len0seq : seq[int] = @[]
  932. assert allIt(numbers, it < 10) == true
  933. assert allIt(numbers, it < 9) == false
  934. assert allIt(len0seq, false) == true
  935. assert allIt(anumbers, it < 10) == true
  936. assert allIt(anumbers, it < 9) == false
  937. block: # any
  938. let
  939. numbers = @[1, 4, 5, 8, 9, 7, 4]
  940. anumbers = [1, 4, 5, 8, 9, 7, 4]
  941. len0seq : seq[int] = @[]
  942. assert any(numbers, proc (x: int): bool = return x > 8) == true
  943. assert any(numbers, proc (x: int): bool = return x > 9) == false
  944. assert any(len0seq, proc (x: int): bool = return true) == false
  945. assert any(anumbers, proc (x: int): bool = return x > 8) == true
  946. assert any(anumbers, proc (x: int): bool = return x > 9) == false
  947. block: # anyIt
  948. let
  949. numbers = @[1, 4, 5, 8, 9, 7, 4]
  950. anumbers = [1, 4, 5, 8, 9, 7, 4]
  951. len0seq : seq[int] = @[]
  952. assert anyIt(numbers, it > 8) == true
  953. assert anyIt(numbers, it > 9) == false
  954. assert anyIt(len0seq, true) == false
  955. assert anyIt(anumbers, it > 8) == true
  956. assert anyIt(anumbers, it > 9) == false
  957. block: # toSeq test
  958. let
  959. numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
  960. odd_numbers = toSeq(filter(numeric) do (x: int) -> bool:
  961. if x mod 2 == 1:
  962. result = true)
  963. assert odd_numbers == @[1, 3, 5, 7, 9]
  964. block:
  965. # tests https://github.com/nim-lang/Nim/issues/7187
  966. counter = 0
  967. let ret = toSeq(@[1, 2, 3].identity().filter(proc (x: int): bool = x < 3))
  968. doAssert ret == @[1, 2]
  969. doAssert counter == 1
  970. block: # foldl tests
  971. let
  972. numbers = @[5, 9, 11]
  973. addition = foldl(numbers, a + b)
  974. subtraction = foldl(numbers, a - b)
  975. multiplication = foldl(numbers, a * b)
  976. words = @["nim", "is", "cool"]
  977. concatenation = foldl(words, a & b)
  978. assert addition == 25, "Addition is (((5)+9)+11)"
  979. assert subtraction == -15, "Subtraction is (((5)-9)-11)"
  980. assert multiplication == 495, "Multiplication is (((5)*9)*11)"
  981. assert concatenation == "nimiscool"
  982. block: # foldr tests
  983. let
  984. numbers = @[5, 9, 11]
  985. addition = foldr(numbers, a + b)
  986. subtraction = foldr(numbers, a - b)
  987. multiplication = foldr(numbers, a * b)
  988. words = @["nim", "is", "cool"]
  989. concatenation = foldr(words, a & b)
  990. assert addition == 25, "Addition is (5+(9+(11)))"
  991. assert subtraction == 7, "Subtraction is (5-(9-(11)))"
  992. assert multiplication == 495, "Multiplication is (5*(9*(11)))"
  993. assert concatenation == "nimiscool"
  994. block: # mapIt + applyIt test
  995. counter = 0
  996. var
  997. nums = @[1, 2, 3, 4]
  998. strings = nums.identity.mapIt($(4 * it))
  999. doAssert counter == 1
  1000. nums.applyIt(it * 3)
  1001. assert nums[0] + nums[3] == 15
  1002. assert strings[2] == "12"
  1003. block: # newSeqWith tests
  1004. var seq2D = newSeqWith(4, newSeq[bool](2))
  1005. seq2D[0][0] = true
  1006. seq2D[1][0] = true
  1007. seq2D[0][1] = true
  1008. doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
  1009. block: # mapLiterals tests
  1010. let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int)
  1011. doAssert x is array[4, int]
  1012. doAssert mapLiterals((1, ("abc"), 2), float, nested=false) == (float(1), "abc", float(2))
  1013. doAssert mapLiterals(([1], ("abc"), 2), `$`, nested=true) == (["1"], "abc", "2")
  1014. block: # mapIt with openArray
  1015. counter = 0
  1016. proc foo(x: openArray[int]): seq[int] = x.mapIt(it * 10)
  1017. doAssert foo([identity(1),identity(2)]) == @[10, 20]
  1018. doAssert counter == 2
  1019. block: # mapIt with direct openArray
  1020. proc foo1(x: openArray[int]): seq[int] = x.mapIt(it * 10)
  1021. counter = 0
  1022. doAssert foo1(openArray[int]([identity(1),identity(2)])) == @[10,20]
  1023. doAssert counter == 2
  1024. # Corner cases (openArray litterals should not be common)
  1025. template foo2(x: openArray[int]): seq[int] = x.mapIt(it * 10)
  1026. counter = 0
  1027. doAssert foo2(openArray[int]([identity(1),identity(2)])) == @[10,20]
  1028. # TODO: this fails; not sure how to fix this case
  1029. # doAssert counter == 2
  1030. counter = 0
  1031. doAssert openArray[int]([identity(1), identity(2)]).mapIt(it) == @[1,2]
  1032. # ditto
  1033. # doAssert counter == 2
  1034. block: # mapIt empty test, see https://github.com/nim-lang/Nim/pull/8584#pullrequestreview-144723468
  1035. # NOTE: `[].mapIt(it)` is illegal, just as `let a = @[]` is (lacks type
  1036. # of elements)
  1037. doAssert: not compiles(mapIt(@[], it))
  1038. doAssert: not compiles(mapIt([], it))
  1039. doAssert newSeq[int](0).mapIt(it) == @[]
  1040. block: # mapIt redifinition check, see https://github.com/nim-lang/Nim/issues/8580
  1041. let s2 = [1,2].mapIt(it)
  1042. doAssert s2 == @[1,2]
  1043. block:
  1044. counter = 0
  1045. doAssert [1,2].identity().mapIt(it*2).mapIt(it*10) == @[20, 40]
  1046. # https://github.com/nim-lang/Nim/issues/7187 test case
  1047. doAssert counter == 1
  1048. block: # mapIt with invalid RHS for `let` (#8566)
  1049. type X = enum
  1050. A, B
  1051. doAssert mapIt(X, $it) == @["A", "B"]
  1052. block:
  1053. # bug #9093
  1054. let inp = "a:b,c:d"
  1055. let outp = inp.split(",").mapIt(it.split(":"))
  1056. doAssert outp == @[@["a", "b"], @["c", "d"]]
  1057. when not defined(testing):
  1058. echo "Finished doc tests"