tsequtils.nim 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. import std/sequtils
  2. import strutils
  3. from algorithm import sorted
  4. # helper for testing double substitution side effects which are handled
  5. # by `evalOnceAs`
  6. var counter = 0
  7. proc identity[T](a: T): auto =
  8. counter.inc
  9. a
  10. block: # concat test
  11. let
  12. s1 = @[1, 2, 3]
  13. s2 = @[4, 5]
  14. s3 = @[6, 7]
  15. total = concat(s1, s2, s3)
  16. assert total == @[1, 2, 3, 4, 5, 6, 7]
  17. block: # count test
  18. let
  19. s1 = @[1, 2, 3, 2]
  20. s2 = @['a', 'b', 'x', 'a']
  21. a1 = [1, 2, 3, 2]
  22. a2 = ['a', 'b', 'x', 'a']
  23. r0 = count(s1, 0)
  24. r1 = count(s1, 1)
  25. r2 = count(s1, 2)
  26. r3 = count(s2, 'y')
  27. r4 = count(s2, 'x')
  28. r5 = count(s2, 'a')
  29. ar0 = count(a1, 0)
  30. ar1 = count(a1, 1)
  31. ar2 = count(a1, 2)
  32. ar3 = count(a2, 'y')
  33. ar4 = count(a2, 'x')
  34. ar5 = count(a2, 'a')
  35. assert r0 == 0
  36. assert r1 == 1
  37. assert r2 == 2
  38. assert r3 == 0
  39. assert r4 == 1
  40. assert r5 == 2
  41. assert ar0 == 0
  42. assert ar1 == 1
  43. assert ar2 == 2
  44. assert ar3 == 0
  45. assert ar4 == 1
  46. assert ar5 == 2
  47. block: # cycle tests
  48. let
  49. a = @[1, 2, 3]
  50. b: seq[int] = @[]
  51. c = [1, 2, 3]
  52. doAssert a.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
  53. doAssert a.cycle(0) == @[]
  54. #doAssert a.cycle(-1) == @[] # will not compile!
  55. doAssert b.cycle(3) == @[]
  56. doAssert c.cycle(3) == @[1, 2, 3, 1, 2, 3, 1, 2, 3]
  57. doAssert c.cycle(0) == @[]
  58. block: # repeat tests
  59. assert repeat(10, 5) == @[10, 10, 10, 10, 10]
  60. assert repeat(@[1, 2, 3], 2) == @[@[1, 2, 3], @[1, 2, 3]]
  61. assert repeat([1, 2, 3], 2) == @[[1, 2, 3], [1, 2, 3]]
  62. block: # deduplicates test
  63. let
  64. dup1 = @[1, 1, 3, 4, 2, 2, 8, 1, 4]
  65. dup2 = @["a", "a", "c", "d", "d"]
  66. dup3 = [1, 1, 3, 4, 2, 2, 8, 1, 4]
  67. dup4 = ["a", "a", "c", "d", "d"]
  68. unique1 = deduplicate(dup1)
  69. unique2 = deduplicate(dup2)
  70. unique3 = deduplicate(dup3)
  71. unique4 = deduplicate(dup4)
  72. unique5 = deduplicate(dup1.sorted, true)
  73. unique6 = deduplicate(dup2, true)
  74. unique7 = deduplicate(dup3.sorted, true)
  75. unique8 = deduplicate(dup4, true)
  76. assert unique1 == @[1, 3, 4, 2, 8]
  77. assert unique2 == @["a", "c", "d"]
  78. assert unique3 == @[1, 3, 4, 2, 8]
  79. assert unique4 == @["a", "c", "d"]
  80. assert unique5 == @[1, 2, 3, 4, 8]
  81. assert unique6 == @["a", "c", "d"]
  82. assert unique7 == @[1, 2, 3, 4, 8]
  83. assert unique8 == @["a", "c", "d"]
  84. block: # zip test
  85. let
  86. short = @[1, 2, 3]
  87. long = @[6, 5, 4, 3, 2, 1]
  88. words = @["one", "two", "three"]
  89. ashort = [1, 2, 3]
  90. along = [6, 5, 4, 3, 2, 1]
  91. awords = ["one", "two", "three"]
  92. zip1 = zip(short, long)
  93. zip2 = zip(short, words)
  94. zip3 = zip(ashort, along)
  95. assert zip1 == @[(1, 6), (2, 5), (3, 4)]
  96. assert zip2 == @[(1, "one"), (2, "two"), (3, "three")]
  97. assert zip3 == @[(1, 6), (2, 5), (3, 4)]
  98. assert zip1[2][1] == 4
  99. assert zip2[2][1] == "three"
  100. assert zip3[2][1] == 4
  101. when (NimMajor, NimMinor) <= (1, 0):
  102. let
  103. # In Nim 1.0.x and older, zip returned a seq of tuple strictly
  104. # with fields named "a" and "b".
  105. zipAb = zip(ashort, awords)
  106. assert zipAb == @[(a: 1, b: "one"), (2, "two"), (3, "three")]
  107. assert zipAb[2].b == "three"
  108. else:
  109. let
  110. # As zip returns seq of anonymous tuples, they can be assigned
  111. # to any variable that's a sequence of named tuples too.
  112. zipXy: seq[tuple[x: int, y: string]] = zip(ashort, awords)
  113. zipMn: seq[tuple[m: int, n: string]] = zip(ashort, words)
  114. assert zipXy == @[(x: 1, y: "one"), (2, "two"), (3, "three")]
  115. assert zipMn == @[(m: 1, n: "one"), (2, "two"), (3, "three")]
  116. assert zipXy[2].y == "three"
  117. assert zipMn[2].n == "three"
  118. block: # distribute tests
  119. let numbers = @[1, 2, 3, 4, 5, 6, 7]
  120. doAssert numbers.distribute(3) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
  121. doAssert numbers.distribute(6)[0] == @[1, 2]
  122. doAssert numbers.distribute(6)[5] == @[7]
  123. let a = @[1, 2, 3, 4, 5, 6, 7]
  124. doAssert a.distribute(1, true) == @[@[1, 2, 3, 4, 5, 6, 7]]
  125. doAssert a.distribute(1, false) == @[@[1, 2, 3, 4, 5, 6, 7]]
  126. doAssert a.distribute(2, true) == @[@[1, 2, 3, 4], @[5, 6, 7]]
  127. doAssert a.distribute(2, false) == @[@[1, 2, 3, 4], @[5, 6, 7]]
  128. doAssert a.distribute(3, true) == @[@[1, 2, 3], @[4, 5], @[6, 7]]
  129. doAssert a.distribute(3, false) == @[@[1, 2, 3], @[4, 5, 6], @[7]]
  130. doAssert a.distribute(4, true) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
  131. doAssert a.distribute(4, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7]]
  132. doAssert a.distribute(5, true) == @[@[1, 2], @[3, 4], @[5], @[6], @[7]]
  133. doAssert a.distribute(5, false) == @[@[1, 2], @[3, 4], @[5, 6], @[7], @[]]
  134. doAssert a.distribute(6, true) == @[@[1, 2], @[3], @[4], @[5], @[6], @[7]]
  135. doAssert a.distribute(6, false) == @[
  136. @[1, 2], @[3, 4], @[5, 6], @[7], @[], @[]]
  137. doAssert a.distribute(8, false) == a.distribute(8, true)
  138. doAssert a.distribute(90, false) == a.distribute(90, true)
  139. var b = @[0]
  140. for f in 1 .. 25: b.add(f)
  141. doAssert b.distribute(5, true)[4].len == 5
  142. doAssert b.distribute(5, false)[4].len == 2
  143. block: # map test
  144. let
  145. numbers = @[1, 4, 5, 8, 9, 7, 4]
  146. anumbers = [1, 4, 5, 8, 9, 7, 4]
  147. m1 = map(numbers, proc(x: int): int = 2*x)
  148. m2 = map(anumbers, proc(x: int): int = 2*x)
  149. assert m1 == @[2, 8, 10, 16, 18, 14, 8]
  150. assert m2 == @[2, 8, 10, 16, 18, 14, 8]
  151. block: # apply test
  152. var a = @["1", "2", "3", "4"]
  153. apply(a, proc(x: var string) = x &= "42")
  154. assert a == @["142", "242", "342", "442"]
  155. block: # filter proc test
  156. let
  157. colors = @["red", "yellow", "black"]
  158. acolors = ["red", "yellow", "black"]
  159. f1 = filter(colors, proc(x: string): bool = x.len < 6)
  160. f2 = filter(colors) do (x: string) -> bool: x.len > 5
  161. f3 = filter(acolors, proc(x: string): bool = x.len < 6)
  162. f4 = filter(acolors) do (x: string) -> bool: x.len > 5
  163. assert f1 == @["red", "black"]
  164. assert f2 == @["yellow"]
  165. assert f3 == @["red", "black"]
  166. assert f4 == @["yellow"]
  167. block: # filter iterator test
  168. let numbers = @[1, 4, 5, 8, 9, 7, 4]
  169. let anumbers = [1, 4, 5, 8, 9, 7, 4]
  170. assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
  171. @[4, 8, 4]
  172. assert toSeq(filter(anumbers, proc (x: int): bool = x mod 2 == 0)) ==
  173. @[4, 8, 4]
  174. block: # keepIf test
  175. var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
  176. keepIf(floats, proc(x: float): bool = x > 10)
  177. assert floats == @[13.0, 12.5, 10.1]
  178. block: # delete tests
  179. let outcome = @[1, 1, 1, 1, 1, 1, 1, 1]
  180. var dest = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1]
  181. dest.delete(3, 8)
  182. assert outcome == dest, """\
  183. Deleting range 3-9 from [1,1,1,2,2,2,2,2,2,1,1,1,1,1]
  184. is [1,1,1,1,1,1,1,1]"""
  185. var x = @[1, 2, 3]
  186. x.delete(100, 100)
  187. assert x == @[1, 2, 3]
  188. block: # insert tests
  189. var dest = @[1, 1, 1, 1, 1, 1, 1, 1]
  190. let
  191. src = @[2, 2, 2, 2, 2, 2]
  192. outcome = @[1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1]
  193. dest.insert(src, 3)
  194. assert dest == outcome, """\
  195. Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
  196. at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
  197. block: # filterIt test
  198. let
  199. temperatures = @[-272.15, -2.0, 24.5, 44.31, 99.9, -113.44]
  200. acceptable = filterIt(temperatures, it < 50 and it > -10)
  201. notAcceptable = filterIt(temperatures, it > 50 or it < -10)
  202. assert acceptable == @[-2.0, 24.5, 44.31]
  203. assert notAcceptable == @[-272.15, 99.9, -113.44]
  204. block: # keepItIf test
  205. var candidates = @["foo", "bar", "baz", "foobar"]
  206. keepItIf(candidates, it.len == 3 and it[0] == 'b')
  207. assert candidates == @["bar", "baz"]
  208. block: # all
  209. let
  210. numbers = @[1, 4, 5, 8, 9, 7, 4]
  211. anumbers = [1, 4, 5, 8, 9, 7, 4]
  212. len0seq: seq[int] = @[]
  213. assert all(numbers, proc (x: int): bool = return x < 10) == true
  214. assert all(numbers, proc (x: int): bool = return x < 9) == false
  215. assert all(len0seq, proc (x: int): bool = return false) == true
  216. assert all(anumbers, proc (x: int): bool = return x < 10) == true
  217. assert all(anumbers, proc (x: int): bool = return x < 9) == false
  218. block: # allIt
  219. let
  220. numbers = @[1, 4, 5, 8, 9, 7, 4]
  221. anumbers = [1, 4, 5, 8, 9, 7, 4]
  222. len0seq: seq[int] = @[]
  223. assert allIt(numbers, it < 10) == true
  224. assert allIt(numbers, it < 9) == false
  225. assert allIt(len0seq, false) == true
  226. assert allIt(anumbers, it < 10) == true
  227. assert allIt(anumbers, it < 9) == false
  228. block: # any
  229. let
  230. numbers = @[1, 4, 5, 8, 9, 7, 4]
  231. anumbers = [1, 4, 5, 8, 9, 7, 4]
  232. len0seq: seq[int] = @[]
  233. assert any(numbers, proc (x: int): bool = return x > 8) == true
  234. assert any(numbers, proc (x: int): bool = return x > 9) == false
  235. assert any(len0seq, proc (x: int): bool = return true) == false
  236. assert any(anumbers, proc (x: int): bool = return x > 8) == true
  237. assert any(anumbers, proc (x: int): bool = return x > 9) == false
  238. block: # anyIt
  239. let
  240. numbers = @[1, 4, 5, 8, 9, 7, 4]
  241. anumbers = [1, 4, 5, 8, 9, 7, 4]
  242. len0seq: seq[int] = @[]
  243. assert anyIt(numbers, it > 8) == true
  244. assert anyIt(numbers, it > 9) == false
  245. assert anyIt(len0seq, true) == false
  246. assert anyIt(anumbers, it > 8) == true
  247. assert anyIt(anumbers, it > 9) == false
  248. block: # toSeq test
  249. block:
  250. let
  251. numeric = @[1, 2, 3, 4, 5, 6, 7, 8, 9]
  252. oddNumbers = toSeq(filter(numeric) do (x: int) -> bool:
  253. if x mod 2 == 1:
  254. result = true)
  255. assert oddNumbers == @[1, 3, 5, 7, 9]
  256. block:
  257. doAssert [1, 2].toSeq == @[1, 2]
  258. doAssert @[1, 2].toSeq == @[1, 2]
  259. doAssert @[1, 2].toSeq == @[1, 2]
  260. doAssert toSeq(@[1, 2]) == @[1, 2]
  261. block:
  262. iterator myIter(seed: int): auto =
  263. for i in 0..<seed:
  264. yield i
  265. doAssert toSeq(myIter(2)) == @[0, 1]
  266. block:
  267. iterator myIter(): auto {.inline.} =
  268. yield 1
  269. yield 2
  270. doAssert myIter.toSeq == @[1, 2]
  271. doAssert toSeq(myIter) == @[1, 2]
  272. block:
  273. iterator myIter(): int {.closure.} =
  274. yield 1
  275. yield 2
  276. doAssert myIter.toSeq == @[1, 2]
  277. doAssert toSeq(myIter) == @[1, 2]
  278. block:
  279. proc myIter(): auto =
  280. iterator ret(): int {.closure.} =
  281. yield 1
  282. yield 2
  283. result = ret
  284. doAssert myIter().toSeq == @[1, 2]
  285. doAssert toSeq(myIter()) == @[1, 2]
  286. block:
  287. proc myIter(n: int): auto =
  288. var counter = 0
  289. iterator ret(): int {.closure.} =
  290. while counter < n:
  291. yield counter
  292. counter.inc
  293. result = ret
  294. block:
  295. let myIter3 = myIter(3)
  296. doAssert myIter3.toSeq == @[0, 1, 2]
  297. block:
  298. let myIter3 = myIter(3)
  299. doAssert toSeq(myIter3) == @[0, 1, 2]
  300. block:
  301. # makes sure this does not hang forever
  302. doAssert myIter(3).toSeq == @[0, 1, 2]
  303. doAssert toSeq(myIter(3)) == @[0, 1, 2]
  304. block:
  305. # tests https://github.com/nim-lang/Nim/issues/7187
  306. counter = 0
  307. let ret = toSeq(@[1, 2, 3].identity().filter(proc (x: int): bool = x < 3))
  308. doAssert ret == @[1, 2]
  309. doAssert counter == 1
  310. block: # foldl tests
  311. let
  312. numbers = @[5, 9, 11]
  313. addition = foldl(numbers, a + b)
  314. subtraction = foldl(numbers, a - b)
  315. multiplication = foldl(numbers, a * b)
  316. words = @["nim", "is", "cool"]
  317. concatenation = foldl(words, a & b)
  318. assert addition == 25, "Addition is (((5)+9)+11)"
  319. assert subtraction == -15, "Subtraction is (((5)-9)-11)"
  320. assert multiplication == 495, "Multiplication is (((5)*9)*11)"
  321. assert concatenation == "nimiscool"
  322. block: # foldr tests
  323. let
  324. numbers = @[5, 9, 11]
  325. addition = foldr(numbers, a + b)
  326. subtraction = foldr(numbers, a - b)
  327. multiplication = foldr(numbers, a * b)
  328. words = @["nim", "is", "cool"]
  329. concatenation = foldr(words, a & b)
  330. assert addition == 25, "Addition is (5+(9+(11)))"
  331. assert subtraction == 7, "Subtraction is (5-(9-(11)))"
  332. assert multiplication == 495, "Multiplication is (5*(9*(11)))"
  333. assert concatenation == "nimiscool"
  334. doAssert toSeq(1..3).foldr(a + b) == 6 # issue #14404
  335. block: # mapIt + applyIt test
  336. counter = 0
  337. var
  338. nums = @[1, 2, 3, 4]
  339. strings = nums.identity.mapIt($(4 * it))
  340. doAssert counter == 1
  341. nums.applyIt(it * 3)
  342. assert nums[0] + nums[3] == 15
  343. assert strings[2] == "12"
  344. block: # newSeqWith tests
  345. var seq2D = newSeqWith(4, newSeq[bool](2))
  346. seq2D[0][0] = true
  347. seq2D[1][0] = true
  348. seq2D[0][1] = true
  349. doAssert seq2D == @[@[true, true], @[true, false], @[false, false], @[false, false]]
  350. block: # mapLiterals tests
  351. let x = mapLiterals([0.1, 1.2, 2.3, 3.4], int)
  352. doAssert x is array[4, int]
  353. doAssert mapLiterals((1, ("abc"), 2), float, nested = false) ==
  354. (float(1), "abc", float(2))
  355. doAssert mapLiterals(([1], ("abc"), 2), `$`, nested = true) ==
  356. (["1"], "abc", "2")
  357. block: # mapIt with openArray
  358. counter = 0
  359. proc foo(x: openArray[int]): seq[int] = x.mapIt(it * 10)
  360. doAssert foo([identity(1), identity(2)]) == @[10, 20]
  361. doAssert counter == 2
  362. block: # mapIt with direct openArray
  363. proc foo1(x: openArray[int]): seq[int] = x.mapIt(it * 10)
  364. counter = 0
  365. doAssert foo1(openArray[int]([identity(1), identity(2)])) == @[10, 20]
  366. doAssert counter == 2
  367. # Corner cases (openArray literals should not be common)
  368. template foo2(x: openArray[int]): seq[int] = x.mapIt(it * 10)
  369. counter = 0
  370. doAssert foo2(openArray[int]([identity(1), identity(2)])) == @[10, 20]
  371. # TODO: this fails; not sure how to fix this case
  372. # doAssert counter == 2
  373. counter = 0
  374. doAssert openArray[int]([identity(1), identity(2)]).mapIt(it) == @[1, 2]
  375. # ditto
  376. # doAssert counter == 2
  377. block: # mapIt empty test, see https://github.com/nim-lang/Nim/pull/8584#pullrequestreview-144723468
  378. # NOTE: `[].mapIt(it)` is illegal, just as `let a = @[]` is (lacks type
  379. # of elements)
  380. doAssert: not compiles(mapIt(@[], it))
  381. doAssert: not compiles(mapIt([], it))
  382. doAssert newSeq[int](0).mapIt(it) == @[]
  383. block: # mapIt redifinition check, see https://github.com/nim-lang/Nim/issues/8580
  384. let s2 = [1, 2].mapIt(it)
  385. doAssert s2 == @[1, 2]
  386. block:
  387. counter = 0
  388. doAssert [1, 2].identity().mapIt(it*2).mapIt(it*10) == @[20, 40]
  389. # https://github.com/nim-lang/Nim/issues/7187 test case
  390. doAssert counter == 1
  391. block: # mapIt with invalid RHS for `let` (#8566)
  392. type X = enum
  393. A, B
  394. doAssert mapIt(X, $it) == @["A", "B"]
  395. block:
  396. # bug #9093
  397. let inp = "a:b,c:d"
  398. let outp = inp.split(",").mapIt(it.split(":"))
  399. doAssert outp == @[@["a", "b"], @["c", "d"]]
  400. block:
  401. proc iter(len: int): auto =
  402. result = iterator(): int =
  403. for i in 0..<len:
  404. yield i
  405. doAssert: iter(3).mapIt(2*it).foldl(a + b) == 6
  406. when not defined(testing):
  407. echo "Finished doc tests"