From fdc19c4d59952216aa4374f82a2135ef6405ae92 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 29 Nov 2020 21:45:21 +0800 Subject: [PATCH 01/15] add merge to algorithm --- changelog.md | 4 ++ lib/pure/algorithm.nim | 60 ++++++++++++++++++++++++++++ tests/stdlib/talgorithm.nim | 79 +++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) diff --git a/changelog.md b/changelog.md index d62e96bbed78b..56c8fda69295d 100644 --- a/changelog.md +++ b/changelog.md @@ -52,6 +52,10 @@ - `writeStackTrace` is available in JS backend now. +- Added `math.copySign`. + +- Added `algorithm.merge`. + ## Language changes - `nimscript` now handles `except Exception as e`. diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 2430e7330c2c6..16c3c279d8c64 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -46,6 +46,8 @@ ## * `sequtils module`_ for working with the built-in seq type ## * `tables module`_ for sorting tables +import std/private/since + type SortOrder* = enum Descending, Ascending @@ -556,6 +558,64 @@ proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool = assert isSorted(e) == false isSorted(a, system.cmp[T], order) +proc merge*[T]( + x, y: openArray[T], cmp: proc(x, y: T +): int {.closure.}, order = SortOrder.Ascending): seq[T] {.since: (1, 5, 1).} = + ## Merges two sorted `openArray`. All of inputs are assumed to be sorted. + ## If you do not wish to provide your own ``cmp``, + ## you may use `system.cmp` or instead call the overloaded + ## version of `merge`, which uses `system.cmp`. + ## + ## **See also:** + ## * `merge proc<#merge,openArray[T],openArray[T]>`_ + runnableExamples: + let x = @[1, 3, 6] + let y = @[2, 3, 4] + + let res = x.merge(y, system.cmp[int]) + assert res.isSorted + assert res == @[1, 2, 3, 3, 4, 6] + let + size_x = x.len + size_y = y.len + + result = newSeqOfCap[T](size_x + size_y) + var + index_x = 0 + index_y = 0 + while true: + if index_x == size_x: + result.add y[index_y .. ^1] + return + + if index_y == size_y: + result.add x[index_x .. ^1] + return + + let item_x = x[index_x] + let item_y = y[index_y] + + if cmp(item_x, item_y) * order > 0: + result.add item_y + inc index_y + else: + result.add item_x + inc index_x + +proc merge*[T](x, y: openArray[T], order = SortOrder.Ascending): seq[T] {.since: (1, 5, 1).} = + ## Shortcut version of ``merge`` that uses ``system.cmp[T]`` as the comparison function. + ## + ## **See also:** + ## * `merge proc<#merge,openArray[T],openArray[T],proc(T,T)>`_ + runnableExamples: + let x = [5,10,15,20,25] + let y = [50,40,30,20,10].sorted + + let res = x.merge(y) + assert res.isSorted + assert res == @[5, 10, 10, 15, 20, 20, 25, 30, 40, 50] + merge(x, y, system.cmp, order) + proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = ## Produces the Cartesian product of the array. Warning: complexity ## may explode. diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index 9dec68f032ec3..f1618215e7b31 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -113,3 +113,82 @@ block: doAssert binarySearch(moreData, 6) == -1 doAssert binarySearch(moreData, 4711) == 4 doAssert binarySearch(moreData, 4712) == -1 + +# merge +block: + var x = @[1, 7, 8, 11, 21, 33, 45, 99] + var y = @[6, 7, 9, 12, 57, 66] + + let merged = merge(x, y) + doAssert merged.issorted + doAssert merged == @[1, 6, 7, 7, 8, 9, 11, 12, 21, 33, 45, 57, 66, 99] + +block: + var x = @[111, 88, 76, 56, 45, 31, 22, 19, 11, 3] + var y = @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13] + + let merged = merge(x, y, SortOrder.Descending) + doAssert merged.issorted(SortOrder.Descending) + doAssert merged == @[111, 99, 88, 85, 83, 82, 76, 69, 64, 56, 48, 45, 42, 33, 31, 31, 26, 22, 19, 13, 11, 3] + # doAssert merged == @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13, 111, 88, 76, 56, 45, 31, 22, 19, 11, 3] + +block: + var x: seq[int] = @[] + var y = @[1] + + let merged = merge(x, y) + doAssert merged.issorted + doAssert merged.issorted(SortOrder.Descending) + doAssert merged == @[1] + +block: + var x = [1, 3, 5, 5, 7] + var y: seq[int] = @[] + + let merged = merge(x, y) + doAssert merged.issorted + doAssert merged == @x + +block: + var x: array[0, int] + var y = [1, 4, 6, 7, 9] + + let merged = merge(x, y) + doAssert merged.issorted + doAssert merged == @y + +block: + var x: array[0, int] + var y: array[0, int] + + let merged = merge(x, y) + doAssert merged.issorted + doAssert merged.len == 0 + +block: + var x: seq[int] + var y: seq[int] + + let merged = merge(x, y) + doAssert merged.issorted + doAssert merged.len == 0 + +block: + type + Record = object + id: int + + proc r(id: int): Record = + Record(id: id) + + proc cmp(x, y: Record): int = + if x.id == y.id: return 0 + if x.id < y.id: return -1 + result = 1 + + var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)] + var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] + + let merged = merge(x, y, cmp) + doAssert merged.issorted(cmp) + doAssert merged.len == 12 From 89197d6aff0c6ac3fb3da6485ed1918ef49e5123 Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 29 Nov 2020 21:47:37 +0800 Subject: [PATCH 02/15] clean --- changelog.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/changelog.md b/changelog.md index 56c8fda69295d..755f1b78cb33f 100644 --- a/changelog.md +++ b/changelog.md @@ -52,8 +52,6 @@ - `writeStackTrace` is available in JS backend now. -- Added `math.copySign`. - - Added `algorithm.merge`. ## Language changes From 2dee3786bb8aa6c438f35ffc97887e9c7d85c31c Mon Sep 17 00:00:00 2001 From: flywind Date: Sun, 29 Nov 2020 21:59:56 +0800 Subject: [PATCH 03/15] small --- lib/pure/algorithm.nim | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 16c3c279d8c64..87b1631e793ba 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -580,9 +580,11 @@ proc merge*[T]( size_y = y.len result = newSeqOfCap[T](size_x + size_y) + var index_x = 0 index_y = 0 + while true: if index_x == size_x: result.add y[index_y .. ^1] From 3251630cd9db1270ec29d6beb876981a4e395b0c Mon Sep 17 00:00:00 2001 From: flywind Date: Mon, 30 Nov 2020 09:20:26 +0800 Subject: [PATCH 04/15] more --- lib/pure/algorithm.nim | 44 ++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 87b1631e793ba..8887eb9109d5b 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -575,34 +575,44 @@ proc merge*[T]( let res = x.merge(y, system.cmp[int]) assert res.isSorted assert res == @[1, 2, 3, 3, 4, 6] + let - size_x = x.len - size_y = y.len - - result = newSeqOfCap[T](size_x + size_y) + sizeX = x.len + sizeY = y.len + + result = newSeq[T](sizeX + sizeY) var - index_x = 0 - index_y = 0 + ix = 0 + iy = 0 + i = 0 while true: - if index_x == size_x: - result.add y[index_y .. ^1] + if ix == sizeX: + while iy < sizeY: + result[i] = y[iy] + inc i + inc iy return - if index_y == size_y: - result.add x[index_x .. ^1] + if iy == sizeY: + while ix < sizeX: + result[i] = x[ix] + inc i + inc ix return - let item_x = x[index_x] - let item_y = y[index_y] + let itemX = x[ix] + let itemY = y[iy] - if cmp(item_x, item_y) * order > 0: - result.add item_y - inc index_y + if cmp(itemX, itemY) * order > 0: + result[i] = itemY + inc iy else: - result.add item_x - inc index_x + result[i] = itemX + inc ix + + inc i proc merge*[T](x, y: openArray[T], order = SortOrder.Ascending): seq[T] {.since: (1, 5, 1).} = ## Shortcut version of ``merge`` that uses ``system.cmp[T]`` as the comparison function. From 24a05caf775e9b86b7b1f96d8a856774c74f1b0e Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 30 Nov 2020 10:14:56 +0800 Subject: [PATCH 05/15] Apply suggestions from code review --- lib/pure/algorithm.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 8887eb9109d5b..b1645317ab895 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -561,7 +561,7 @@ proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool = proc merge*[T]( x, y: openArray[T], cmp: proc(x, y: T ): int {.closure.}, order = SortOrder.Ascending): seq[T] {.since: (1, 5, 1).} = - ## Merges two sorted `openArray`. All of inputs are assumed to be sorted. + ## Merges two sorted `openArray`. `x` and `y` are assumed to be sorted. ## If you do not wish to provide your own ``cmp``, ## you may use `system.cmp` or instead call the overloaded ## version of `merge`, which uses `system.cmp`. @@ -615,7 +615,7 @@ proc merge*[T]( inc i proc merge*[T](x, y: openArray[T], order = SortOrder.Ascending): seq[T] {.since: (1, 5, 1).} = - ## Shortcut version of ``merge`` that uses ``system.cmp[T]`` as the comparison function. + ## Shortcut version of `merge` that uses `system.cmp[T]` as the comparison function. ## ## **See also:** ## * `merge proc<#merge,openArray[T],openArray[T],proc(T,T)>`_ From 6f37e6c525df264cb75ab7cce009190f88f1fa1d Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 30 Nov 2020 10:30:22 +0800 Subject: [PATCH 06/15] Update lib/pure/algorithm.nim --- lib/pure/algorithm.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index b1645317ab895..246d3fdb2caf2 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -562,7 +562,7 @@ proc merge*[T]( x, y: openArray[T], cmp: proc(x, y: T ): int {.closure.}, order = SortOrder.Ascending): seq[T] {.since: (1, 5, 1).} = ## Merges two sorted `openArray`. `x` and `y` are assumed to be sorted. - ## If you do not wish to provide your own ``cmp``, + ## If you do not wish to provide your own `cmp`, ## you may use `system.cmp` or instead call the overloaded ## version of `merge`, which uses `system.cmp`. ## From cb4843f30140c1b005e9c2c0b16c5d5427d7d892 Mon Sep 17 00:00:00 2001 From: flywind <43030857+xflywind@users.noreply.github.com> Date: Mon, 30 Nov 2020 15:39:33 +0800 Subject: [PATCH 07/15] Apply suggestions from code review Co-authored-by: ee7 <45465154+ee7@users.noreply.github.com> --- tests/stdlib/talgorithm.nim | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index f1618215e7b31..c5419d9fb3525 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -120,7 +120,7 @@ block: var y = @[6, 7, 9, 12, 57, 66] let merged = merge(x, y) - doAssert merged.issorted + doAssert merged.isSorted doAssert merged == @[1, 6, 7, 7, 8, 9, 11, 12, 21, 33, 45, 57, 66, 99] block: @@ -128,7 +128,7 @@ block: var y = @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13] let merged = merge(x, y, SortOrder.Descending) - doAssert merged.issorted(SortOrder.Descending) + doAssert merged.isSorted(SortOrder.Descending) doAssert merged == @[111, 99, 88, 85, 83, 82, 76, 69, 64, 56, 48, 45, 42, 33, 31, 31, 26, 22, 19, 13, 11, 3] # doAssert merged == @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13, 111, 88, 76, 56, 45, 31, 22, 19, 11, 3] @@ -137,8 +137,8 @@ block: var y = @[1] let merged = merge(x, y) - doAssert merged.issorted - doAssert merged.issorted(SortOrder.Descending) + doAssert merged.isSorted + doAssert merged.isSorted(SortOrder.Descending) doAssert merged == @[1] block: @@ -146,7 +146,7 @@ block: var y: seq[int] = @[] let merged = merge(x, y) - doAssert merged.issorted + doAssert merged.isSorted doAssert merged == @x block: @@ -154,7 +154,7 @@ block: var y = [1, 4, 6, 7, 9] let merged = merge(x, y) - doAssert merged.issorted + doAssert merged.isSorted doAssert merged == @y block: @@ -162,7 +162,7 @@ block: var y: array[0, int] let merged = merge(x, y) - doAssert merged.issorted + doAssert merged.isSorted doAssert merged.len == 0 block: @@ -170,7 +170,7 @@ block: var y: seq[int] let merged = merge(x, y) - doAssert merged.issorted + doAssert merged.isSorted doAssert merged.len == 0 block: @@ -190,5 +190,5 @@ block: var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] let merged = merge(x, y, cmp) - doAssert merged.issorted(cmp) + doAssert merged.isSorted(cmp) doAssert merged.len == 12 From bad7f05a6ab2f8f406ef79c7054c31a5ed681abd Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 1 Dec 2020 09:53:58 +0800 Subject: [PATCH 08/15] let's go --- lib/pure/algorithm.nim | 31 ++++++++------ tests/stdlib/talgorithm.nim | 85 ++++++++++++++++++++++++++++++++----- 2 files changed, 92 insertions(+), 24 deletions(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 246d3fdb2caf2..7fb59a003cf9a 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -559,28 +559,30 @@ proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool = isSorted(a, system.cmp[T], order) proc merge*[T]( - x, y: openArray[T], cmp: proc(x, y: T -): int {.closure.}, order = SortOrder.Ascending): seq[T] {.since: (1, 5, 1).} = + result: var seq[T], + x, y: openArray[T], cmp: proc(x, y: T): int {.closure.} +) {.since: (1, 5, 1).} = ## Merges two sorted `openArray`. `x` and `y` are assumed to be sorted. ## If you do not wish to provide your own `cmp`, ## you may use `system.cmp` or instead call the overloaded ## version of `merge`, which uses `system.cmp`. ## ## **See also:** - ## * `merge proc<#merge,openArray[T],openArray[T]>`_ + ## * `merge proc<#merge,var seq[T],openArray[T],openArray[T]>`_ runnableExamples: let x = @[1, 3, 6] let y = @[2, 3, 4] - let res = x.merge(y, system.cmp[int]) - assert res.isSorted - assert res == @[1, 2, 3, 3, 4, 6] + var merged: seq[int] + merged.merge(x, y, system.cmp[int]) + assert merged.isSorted + assert merged == @[1, 2, 3, 3, 4, 6] let sizeX = x.len sizeY = y.len - result = newSeq[T](sizeX + sizeY) + result.setlen(sizeX + sizeY) var ix = 0 @@ -605,7 +607,7 @@ proc merge*[T]( let itemX = x[ix] let itemY = y[iy] - if cmp(itemX, itemY) * order > 0: + if cmp(itemX, itemY) > 0: result[i] = itemY inc iy else: @@ -614,19 +616,20 @@ proc merge*[T]( inc i -proc merge*[T](x, y: openArray[T], order = SortOrder.Ascending): seq[T] {.since: (1, 5, 1).} = +proc merge*[T](result: var seq[T], x, y: openArray[T]) {.since: (1, 5, 1).} = ## Shortcut version of `merge` that uses `system.cmp[T]` as the comparison function. ## ## **See also:** - ## * `merge proc<#merge,openArray[T],openArray[T],proc(T,T)>`_ + ## * `merge proc<#merge,var seq[T],openArray[T],openArray[T],proc(T,T)>`_ runnableExamples: let x = [5,10,15,20,25] let y = [50,40,30,20,10].sorted - let res = x.merge(y) - assert res.isSorted - assert res == @[5, 10, 10, 15, 20, 20, 25, 30, 40, 50] - merge(x, y, system.cmp, order) + var merged: seq[int] + merged.merge(x, y) + assert merged.isSorted + assert merged == @[5, 10, 10, 15, 20, 20, 25, 30, 40, 50] + merge(result, x, y, system.cmp) proc product*[T](x: openArray[seq[T]]): seq[seq[T]] = ## Produces the Cartesian product of the array. Warning: complexity diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index c5419d9fb3525..cb93ea1ed7837 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -119,7 +119,8 @@ block: var x = @[1, 7, 8, 11, 21, 33, 45, 99] var y = @[6, 7, 9, 12, 57, 66] - let merged = merge(x, y) + var merged: seq[int] + merged.merge(x, y) doAssert merged.isSorted doAssert merged == @[1, 6, 7, 7, 8, 9, 11, 12, 21, 33, 45, 57, 66, 99] @@ -127,16 +128,17 @@ block: var x = @[111, 88, 76, 56, 45, 31, 22, 19, 11, 3] var y = @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13] - let merged = merge(x, y, SortOrder.Descending) - doAssert merged.isSorted(SortOrder.Descending) + var merged: seq[int] + merged.merge(x, y, proc (x, y: int): int = -system.cmp(x, y)) + doAssert merged.isSorted(proc (x, y: int): int = -system.cmp(x, y)) doAssert merged == @[111, 99, 88, 85, 83, 82, 76, 69, 64, 56, 48, 45, 42, 33, 31, 31, 26, 22, 19, 13, 11, 3] - # doAssert merged == @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13, 111, 88, 76, 56, 45, 31, 22, 19, 11, 3] block: var x: seq[int] = @[] var y = @[1] - let merged = merge(x, y) + var merged: seq[int] + merged.merge(x, y) doAssert merged.isSorted doAssert merged.isSorted(SortOrder.Descending) doAssert merged == @[1] @@ -145,15 +147,27 @@ block: var x = [1, 3, 5, 5, 7] var y: seq[int] = @[] - let merged = merge(x, y) + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged == @x + +block: + var x = [1, 3, 5, 5, 7] + var y: seq[int] = @[] + + var merged: seq[int] = @[1, 2, 3, 5, 6, 56, 99, 2, 34] + merged.merge(x, y) doAssert merged.isSorted doAssert merged == @x + block: var x: array[0, int] var y = [1, 4, 6, 7, 9] - let merged = merge(x, y) + var merged: seq[int] + merged.merge(x, y) doAssert merged.isSorted doAssert merged == @y @@ -161,7 +175,17 @@ block: var x: array[0, int] var y: array[0, int] - let merged = merge(x, y) + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged.len == 0 + +block: + var x: array[0, int] + var y: array[0, int] + + var merged: seq[int] = @[99, 99, 99] + merged.merge(x, y) doAssert merged.isSorted doAssert merged.len == 0 @@ -169,7 +193,8 @@ block: var x: seq[int] var y: seq[int] - let merged = merge(x, y) + var merged: seq[int] + merged.merge(x, y) doAssert merged.isSorted doAssert merged.len == 0 @@ -189,6 +214,46 @@ block: var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)] var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] - let merged = merge(x, y, cmp) + var merged: seq[Record] = @[] + merged.merge(x, y, cmp) doAssert merged.isSorted(cmp) doAssert merged.len == 12 + +block: + type + Record = object + id: int + + proc r(id: int): Record = + Record(id: id) + + proc ascendingCmp(x, y: Record): int = + if x.id == y.id: return 0 + if x.id < y.id: return -1 + result = 1 + + proc descendingCmp(x, y: Record): int = + if x.id == y.id: return 0 + if x.id < y.id: return 1 + result = -1 + + var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)] + var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] + + var merged: seq[Record] + merged.merge(x, y, ascendingCmp) + doAssert merged.isSorted(ascendingCmp) + doAssert merged.len == 12 + + reverse(x) + reverse(y) + merged.merge(x, y, descendingCmp) + doAssert merged.isSorted(descendingCmp) + doAssert merged.len == 12 + + + reverse(x) + reverse(y) + merged.merge(x, y, proc (x, y: Record): int = -descendingCmp(x, y)) + doAssert merged.isSorted(proc (x, y: Record): int = -descendingCmp(x, y)) + doAssert merged.len == 12 From c2777bee049bfd48c786877a2db8cdf16127c455 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 1 Dec 2020 10:10:00 +0800 Subject: [PATCH 09/15] morre tests --- lib/pure/algorithm.nim | 6 ++++++ tests/stdlib/talgorithm.nim | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 7fb59a003cf9a..723562010efbb 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -578,6 +578,12 @@ proc merge*[T]( assert merged.isSorted assert merged == @[1, 2, 3, 3, 4, 6] + import sugar + + var res: seq[(int, int)] + res.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0]) + assert res == @[(1, 1), (1, 2)] + let sizeX = x.len sizeY = y.len diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index cb93ea1ed7837..8e5c4e8180a4d 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -257,3 +257,10 @@ block: merged.merge(x, y, proc (x, y: Record): int = -descendingCmp(x, y)) doAssert merged.isSorted(proc (x, y: Record): int = -descendingCmp(x, y)) doAssert merged.len == 12 + + +import sugar + +var x: seq[(int, int)] +x.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0]) +doAssert x == @[(1, 1), (1, 2)] \ No newline at end of file From f2eb87babbb54e4321dd34c81d6c1afe28befbf2 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 1 Dec 2020 10:15:53 +0800 Subject: [PATCH 10/15] fix doc links --- lib/pure/algorithm.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 723562010efbb..c9b363623510e 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -568,7 +568,7 @@ proc merge*[T]( ## version of `merge`, which uses `system.cmp`. ## ## **See also:** - ## * `merge proc<#merge,var seq[T],openArray[T],openArray[T]>`_ + ## * `merge proc<#merge,seq[T],openArray[T],openArray[T]>`_ runnableExamples: let x = @[1, 3, 6] let y = @[2, 3, 4] @@ -626,7 +626,7 @@ proc merge*[T](result: var seq[T], x, y: openArray[T]) {.since: (1, 5, 1).} = ## Shortcut version of `merge` that uses `system.cmp[T]` as the comparison function. ## ## **See also:** - ## * `merge proc<#merge,var seq[T],openArray[T],openArray[T],proc(T,T)>`_ + ## * `merge proc<#merge,seq[T],openArray[T],openArray[T],proc(T,T)>`_ runnableExamples: let x = [5,10,15,20,25] let y = [50,40,30,20,10].sorted From 0624e1d83fc889a889ac06afa5387bee61893690 Mon Sep 17 00:00:00 2001 From: flywind Date: Tue, 1 Dec 2020 10:36:14 +0800 Subject: [PATCH 11/15] follow advice --- tests/stdlib/talgorithm.nim | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index 8e5c4e8180a4d..acfd6f2e071c6 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -122,7 +122,7 @@ block: var merged: seq[int] merged.merge(x, y) doAssert merged.isSorted - doAssert merged == @[1, 6, 7, 7, 8, 9, 11, 12, 21, 33, 45, 57, 66, 99] + doAssert merged == sorted(x & y) block: var x = @[111, 88, 76, 56, 45, 31, 22, 19, 11, 3] @@ -131,7 +131,7 @@ block: var merged: seq[int] merged.merge(x, y, proc (x, y: int): int = -system.cmp(x, y)) doAssert merged.isSorted(proc (x, y: int): int = -system.cmp(x, y)) - doAssert merged == @[111, 99, 88, 85, 83, 82, 76, 69, 64, 56, 48, 45, 42, 33, 31, 31, 26, 22, 19, 13, 11, 3] + doAssert merged == sorted(x & y, SortOrder.Descending) block: var x: seq[int] = @[] @@ -243,24 +243,23 @@ block: var merged: seq[Record] merged.merge(x, y, ascendingCmp) doAssert merged.isSorted(ascendingCmp) - doAssert merged.len == 12 + doAssert merged == sorted(x & y, ascendingCmp) reverse(x) reverse(y) merged.merge(x, y, descendingCmp) doAssert merged.isSorted(descendingCmp) - doAssert merged.len == 12 - + doAssert merged == sorted(x & y, ascendingCmp, SortOrder.Descending) reverse(x) reverse(y) merged.merge(x, y, proc (x, y: Record): int = -descendingCmp(x, y)) doAssert merged.isSorted(proc (x, y: Record): int = -descendingCmp(x, y)) - doAssert merged.len == 12 + doAssert merged == sorted(x & y, ascendingCmp) import sugar var x: seq[(int, int)] x.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0]) -doAssert x == @[(1, 1), (1, 2)] \ No newline at end of file +doAssert x == @[(1, 1), (1, 2)] From 315bbeacbabd9123f4aed8df9de58a133d1b4d15 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 26 Feb 2021 10:54:56 +0800 Subject: [PATCH 12/15] address comments --- lib/pure/algorithm.nim | 8 +- tests/stdlib/talgorithm.nim | 295 ++++++++++++++++++------------------ 2 files changed, 151 insertions(+), 152 deletions(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 92af761bb6176..12e0073541c42 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -576,7 +576,7 @@ proc merge*[T]( let x = @[1, 3, 6] let y = @[2, 3, 4] - var merged: seq[int] + var merged = @[7] # just to illustrate that its content will be discarded merged.merge(x, y, system.cmp[int]) assert merged.isSorted assert merged == @[1, 2, 3, 3, 4, 6] @@ -591,7 +591,7 @@ proc merge*[T]( sizeX = x.len sizeY = y.len - result.setlen(sizeX + sizeY) + result.setLen(sizeX + sizeY) var ix = 0 @@ -616,7 +616,7 @@ proc merge*[T]( let itemX = x[ix] let itemY = y[iy] - if cmp(itemX, itemY) > 0: + if cmp(itemX, itemY) > 0: # to have a stable sort result[i] = itemY inc iy else: @@ -625,7 +625,7 @@ proc merge*[T]( inc i -proc merge*[T](result: var seq[T], x, y: openArray[T]) {.since: (1, 5, 1).} = +proc merge*[T](result: var seq[T], x, y: openArray[T]) {.inline, since: (1, 5, 1).} = ## Shortcut version of `merge` that uses `system.cmp[T]` as the comparison function. ## ## **See also:** diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index 9f6e8e9e38d02..660002dbac977 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -3,7 +3,7 @@ discard """ ''' """ #12928,10456 -import sequtils, algorithm, json +import sequtils, algorithm, json, sugar proc test() = try: @@ -116,150 +116,149 @@ block: # merge block: - var x = @[1, 7, 8, 11, 21, 33, 45, 99] - var y = @[6, 7, 9, 12, 57, 66] - - var merged: seq[int] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged == sorted(x & y) - -block: - var x = @[111, 88, 76, 56, 45, 31, 22, 19, 11, 3] - var y = @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13] - - var merged: seq[int] - merged.merge(x, y, proc (x, y: int): int = -system.cmp(x, y)) - doAssert merged.isSorted(proc (x, y: int): int = -system.cmp(x, y)) - doAssert merged == sorted(x & y, SortOrder.Descending) - -block: - var x: seq[int] = @[] - var y = @[1] - - var merged: seq[int] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged.isSorted(SortOrder.Descending) - doAssert merged == @[1] - -block: - var x = [1, 3, 5, 5, 7] - var y: seq[int] = @[] - - var merged: seq[int] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged == @x - -block: - var x = [1, 3, 5, 5, 7] - var y: seq[int] = @[] - - var merged: seq[int] = @[1, 2, 3, 5, 6, 56, 99, 2, 34] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged == @x - - -block: - var x: array[0, int] - var y = [1, 4, 6, 7, 9] - - var merged: seq[int] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged == @y - -block: - var x: array[0, int] - var y: array[0, int] - - var merged: seq[int] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged.len == 0 - -block: - var x: array[0, int] - var y: array[0, int] - - var merged: seq[int] = @[99, 99, 99] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged.len == 0 - -block: - var x: seq[int] - var y: seq[int] - - var merged: seq[int] - merged.merge(x, y) - doAssert merged.isSorted - doAssert merged.len == 0 - -block: - type - Record = object - id: int - - proc r(id: int): Record = - Record(id: id) - - proc cmp(x, y: Record): int = - if x.id == y.id: return 0 - if x.id < y.id: return -1 - result = 1 - - var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)] - var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] - - var merged: seq[Record] = @[] - merged.merge(x, y, cmp) - doAssert merged.isSorted(cmp) - doAssert merged.len == 12 - -block: - type - Record = object - id: int - - proc r(id: int): Record = - Record(id: id) - - proc ascendingCmp(x, y: Record): int = - if x.id == y.id: return 0 - if x.id < y.id: return -1 - result = 1 - - proc descendingCmp(x, y: Record): int = - if x.id == y.id: return 0 - if x.id < y.id: return 1 - result = -1 - - var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)] - var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] - - var merged: seq[Record] - merged.merge(x, y, ascendingCmp) - doAssert merged.isSorted(ascendingCmp) - doAssert merged == sorted(x & y, ascendingCmp) - - reverse(x) - reverse(y) - merged.merge(x, y, descendingCmp) - doAssert merged.isSorted(descendingCmp) - doAssert merged == sorted(x & y, ascendingCmp, SortOrder.Descending) - - reverse(x) - reverse(y) - merged.merge(x, y, proc (x, y: Record): int = -descendingCmp(x, y)) - doAssert merged.isSorted(proc (x, y: Record): int = -descendingCmp(x, y)) - doAssert merged == sorted(x & y, ascendingCmp) - - -import sugar - -var x: seq[(int, int)] -x.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0]) -doAssert x == @[(1, 1), (1, 2)] + block: + var x = @[1, 7, 8, 11, 21, 33, 45, 99] + var y = @[6, 7, 9, 12, 57, 66] + + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged == sorted(x & y) + + block: + var x = @[111, 88, 76, 56, 45, 31, 22, 19, 11, 3] + var y = @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13] + + var merged: seq[int] + merged.merge(x, y, (x, y) => -system.cmp(x, y)) + doAssert merged.isSorted((x, y) => -system.cmp(x, y)) + doAssert merged == sorted(x & y, SortOrder.Descending) + + block: + var x: seq[int] = @[] + var y = @[1] + + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged.isSorted(SortOrder.Descending) + doAssert merged == @[1] + + block: + var x = [1, 3, 5, 5, 7] + var y: seq[int] = @[] + + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged == @x + + block: + var x = [1, 3, 5, 5, 7] + var y: seq[int] = @[] + + var merged: seq[int] = @[1, 2, 3, 5, 6, 56, 99, 2, 34] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged == @x + + + block: + var x: array[0, int] + var y = [1, 4, 6, 7, 9] + + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged == @y + + block: + var x: array[0, int] + var y: array[0, int] + + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged.len == 0 + + block: + var x: array[0, int] + var y: array[0, int] + + var merged: seq[int] = @[99, 99, 99] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged.len == 0 + + block: + var x: seq[int] + var y: seq[int] + + var merged: seq[int] + merged.merge(x, y) + doAssert merged.isSorted + doAssert merged.len == 0 + + block: + type + Record = object + id: int + + proc r(id: int): Record = + Record(id: id) + + proc cmp(x, y: Record): int = + if x.id == y.id: return 0 + if x.id < y.id: return -1 + result = 1 + + var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)] + var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] + + var merged: seq[Record] = @[] + merged.merge(x, y, cmp) + doAssert merged.isSorted(cmp) + doAssert merged.len == 12 + + block: + type + Record = object + id: int + + proc r(id: int): Record = + Record(id: id) + + proc ascendingCmp(x, y: Record): int = + if x.id == y.id: return 0 + if x.id < y.id: return -1 + result = 1 + + proc descendingCmp(x, y: Record): int = + if x.id == y.id: return 0 + if x.id < y.id: return 1 + result = -1 + + var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)] + var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] + + var merged: seq[Record] + merged.merge(x, y, ascendingCmp) + doAssert merged.isSorted(ascendingCmp) + doAssert merged == sorted(x & y, ascendingCmp) + + reverse(x) + reverse(y) + merged.merge(x, y, descendingCmp) + doAssert merged.isSorted(descendingCmp) + doAssert merged == sorted(x & y, ascendingCmp, SortOrder.Descending) + + reverse(x) + reverse(y) + merged.merge(x, y, proc (x, y: Record): int = -descendingCmp(x, y)) + doAssert merged.isSorted(proc (x, y: Record): int = -descendingCmp(x, y)) + doAssert merged == sorted(x & y, ascendingCmp) + + + var x: seq[(int, int)] + x.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0]) + doAssert x == @[(1, 1), (1, 2)] From 0a6bba4d17e9d37cdeed4728f4fb10f641bcb63e Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 26 Feb 2021 12:19:04 +0800 Subject: [PATCH 13/15] update tests --- tests/stdlib/talgorithm.nim | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index 660002dbac977..54e9b6b5941f2 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -1,9 +1,10 @@ discard """ + targets: "c js" output:'''@["3", "2", "1"] ''' """ #12928,10456 -import sequtils, algorithm, json, sugar +import std/[sequtils, algorithm, json, sugar] proc test() = try: @@ -115,7 +116,7 @@ block: doAssert binarySearch(moreData, 4712) == -1 # merge -block: +proc main() = block: var x = @[1, 7, 8, 11, 21, 33, 45, 99] var y = @[6, 7, 9, 12, 57, 66] @@ -262,3 +263,6 @@ block: var x: seq[(int, int)] x.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0]) doAssert x == @[(1, 1), (1, 2)] + +static: main() +main() From f46058e32ce3665cbf6d39b984aea9eeecd92673 Mon Sep 17 00:00:00 2001 From: flywind Date: Fri, 12 Mar 2021 12:54:57 +0800 Subject: [PATCH 14/15] follow --- lib/pure/algorithm.nim | 33 +++++++++++++++++++++++---------- tests/stdlib/talgorithm.nim | 8 ++++++-- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/lib/pure/algorithm.nim b/lib/pure/algorithm.nim index 48c8a8eb83f27..be2006619cf03 100644 --- a/lib/pure/algorithm.nim +++ b/lib/pure/algorithm.nim @@ -570,33 +570,46 @@ proc merge*[T]( ## you may use `system.cmp` or instead call the overloaded ## version of `merge`, which uses `system.cmp`. ## + ## .. note:: The original data of `result` is not cleared, + ## new data is appended to `result`. + ## ## **See also:** ## * `merge proc<#merge,seq[T],openArray[T],openArray[T]>`_ runnableExamples: let x = @[1, 3, 6] let y = @[2, 3, 4] - var merged = @[7] # just to illustrate that its content will be discarded - merged.merge(x, y, system.cmp[int]) - assert merged.isSorted - assert merged == @[1, 2, 3, 3, 4, 6] + block: + var merged = @[7] # new data is appended to merged sequence + merged.merge(x, y, system.cmp[int]) + assert merged == @[7, 1, 2, 3, 3, 4, 6] - import sugar + block: + var merged = @[7] # if you only want new data, clear merged sequence first + merged.setLen(0) + merged.merge(x, y, system.cmp[int]) + assert merged.isSorted + assert merged == @[1, 2, 3, 3, 4, 6] + + import std/sugar var res: seq[(int, int)] - res.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0]) + res.merge([(1, 1)], [(1, 2)], (a, b) => a[0] - b[0]) assert res == @[(1, 1), (1, 2)] + assert seq[int].default.dup(merge([1, 3], [2, 4])) == @[1, 2, 3, 4] + let sizeX = x.len sizeY = y.len + oldLen = result.len - result.setLen(sizeX + sizeY) + result.setLen(oldLen + sizeX + sizeY) var ix = 0 iy = 0 - i = 0 + i = oldLen while true: if ix == sizeX: @@ -631,8 +644,8 @@ proc merge*[T](result: var seq[T], x, y: openArray[T]) {.inline, since: (1, 5, 1 ## **See also:** ## * `merge proc<#merge,seq[T],openArray[T],openArray[T],proc(T,T)>`_ runnableExamples: - let x = [5,10,15,20,25] - let y = [50,40,30,20,10].sorted + let x = [5, 10, 15, 20, 25] + let y = [50, 40, 30, 20, 10].sorted var merged: seq[int] merged.merge(x, y) diff --git a/tests/stdlib/talgorithm.nim b/tests/stdlib/talgorithm.nim index 54e9b6b5941f2..d49487242e30c 100644 --- a/tests/stdlib/talgorithm.nim +++ b/tests/stdlib/talgorithm.nim @@ -160,8 +160,7 @@ proc main() = var merged: seq[int] = @[1, 2, 3, 5, 6, 56, 99, 2, 34] merged.merge(x, y) - doAssert merged.isSorted - doAssert merged == @x + doAssert merged == @[1, 2, 3, 5, 6, 56, 99, 2, 34, 1, 3, 5, 5, 7] block: @@ -187,6 +186,7 @@ proc main() = var y: array[0, int] var merged: seq[int] = @[99, 99, 99] + merged.setLen(0) merged.merge(x, y) doAssert merged.isSorted doAssert merged.len == 0 @@ -243,18 +243,22 @@ proc main() = var y = @[r(4), r(7), r(12), r(13), r(77), r(99)] var merged: seq[Record] + merged.setLen(0) merged.merge(x, y, ascendingCmp) doAssert merged.isSorted(ascendingCmp) doAssert merged == sorted(x & y, ascendingCmp) reverse(x) reverse(y) + + merged.setLen(0) merged.merge(x, y, descendingCmp) doAssert merged.isSorted(descendingCmp) doAssert merged == sorted(x & y, ascendingCmp, SortOrder.Descending) reverse(x) reverse(y) + merged.setLen(0) merged.merge(x, y, proc (x, y: Record): int = -descendingCmp(x, y)) doAssert merged.isSorted(proc (x, y: Record): int = -descendingCmp(x, y)) doAssert merged == sorted(x & y, ascendingCmp) From 2c73579425a4a1e7d620175f39f171649a546b21 Mon Sep 17 00:00:00 2001 From: flywind Date: Wed, 17 Mar 2021 17:21:28 +0800 Subject: [PATCH 15/15] Update changelog.md --- changelog.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/changelog.md b/changelog.md index d23ce100d690e..793e2e3bd745c 100644 --- a/changelog.md +++ b/changelog.md @@ -82,8 +82,6 @@ - `writeStackTrace` is available in JS backend now. - - - Added `decodeQuery` to `std/uri`. - `strscans.scanf` now supports parsing single characters.