Skip to content

Commit c719d79

Browse files
ringaboutee7
andauthored
add algorithm.merge (#16182)
* add merge to algorithm * Apply suggestions from code review * Update lib/pure/algorithm.nim * Apply suggestions from code review * Update changelog.md Co-authored-by: ee7 <[email protected]>
1 parent 64e6670 commit c719d79

File tree

3 files changed

+255
-1
lines changed

3 files changed

+255
-1
lines changed

changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,9 @@
212212

213213
- `std/options` changed `$some(3)` to `"some(3)"` instead of `"Some(3)"`
214214
and `$none(int)` to `"none(int)"` instead of `"None[int]"`.
215+
216+
- Added `algorithm.merge`.
217+
215218

216219
- Added `std/jsfetch` module [Fetch](https://developer.mozilla.org/docs/Web/API/Fetch_API) wrapper for JavaScript target.
217220

lib/pure/algorithm.nim

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ runnableExamples:
4242
## * `sequtils module<sequtils.html>`_ for working with the built-in seq type
4343
## * `tables module<tables.html>`_ for sorting tables
4444

45+
import std/private/since
46+
4547
type
4648
SortOrder* = enum
4749
Descending, Ascending
@@ -559,6 +561,98 @@ proc isSorted*[T](a: openArray[T], order = SortOrder.Ascending): bool =
559561
assert isSorted(e) == false
560562
isSorted(a, system.cmp[T], order)
561563

564+
proc merge*[T](
565+
result: var seq[T],
566+
x, y: openArray[T], cmp: proc(x, y: T): int {.closure.}
567+
) {.since: (1, 5, 1).} =
568+
## Merges two sorted `openArray`. `x` and `y` are assumed to be sorted.
569+
## If you do not wish to provide your own `cmp`,
570+
## you may use `system.cmp` or instead call the overloaded
571+
## version of `merge`, which uses `system.cmp`.
572+
##
573+
## .. note:: The original data of `result` is not cleared,
574+
## new data is appended to `result`.
575+
##
576+
## **See also:**
577+
## * `merge proc<#merge,seq[T],openArray[T],openArray[T]>`_
578+
runnableExamples:
579+
let x = @[1, 3, 6]
580+
let y = @[2, 3, 4]
581+
582+
block:
583+
var merged = @[7] # new data is appended to merged sequence
584+
merged.merge(x, y, system.cmp[int])
585+
assert merged == @[7, 1, 2, 3, 3, 4, 6]
586+
587+
block:
588+
var merged = @[7] # if you only want new data, clear merged sequence first
589+
merged.setLen(0)
590+
merged.merge(x, y, system.cmp[int])
591+
assert merged.isSorted
592+
assert merged == @[1, 2, 3, 3, 4, 6]
593+
594+
import std/sugar
595+
596+
var res: seq[(int, int)]
597+
res.merge([(1, 1)], [(1, 2)], (a, b) => a[0] - b[0])
598+
assert res == @[(1, 1), (1, 2)]
599+
600+
assert seq[int].default.dup(merge([1, 3], [2, 4])) == @[1, 2, 3, 4]
601+
602+
let
603+
sizeX = x.len
604+
sizeY = y.len
605+
oldLen = result.len
606+
607+
result.setLen(oldLen + sizeX + sizeY)
608+
609+
var
610+
ix = 0
611+
iy = 0
612+
i = oldLen
613+
614+
while true:
615+
if ix == sizeX:
616+
while iy < sizeY:
617+
result[i] = y[iy]
618+
inc i
619+
inc iy
620+
return
621+
622+
if iy == sizeY:
623+
while ix < sizeX:
624+
result[i] = x[ix]
625+
inc i
626+
inc ix
627+
return
628+
629+
let itemX = x[ix]
630+
let itemY = y[iy]
631+
632+
if cmp(itemX, itemY) > 0: # to have a stable sort
633+
result[i] = itemY
634+
inc iy
635+
else:
636+
result[i] = itemX
637+
inc ix
638+
639+
inc i
640+
641+
proc merge*[T](result: var seq[T], x, y: openArray[T]) {.inline, since: (1, 5, 1).} =
642+
## Shortcut version of `merge` that uses `system.cmp[T]` as the comparison function.
643+
##
644+
## **See also:**
645+
## * `merge proc<#merge,seq[T],openArray[T],openArray[T],proc(T,T)>`_
646+
runnableExamples:
647+
let x = [5, 10, 15, 20, 25]
648+
let y = [50, 40, 30, 20, 10].sorted
649+
650+
var merged: seq[int]
651+
merged.merge(x, y)
652+
assert merged.isSorted
653+
assert merged == @[5, 10, 10, 15, 20, 20, 25, 30, 40, 50]
654+
merge(result, x, y, system.cmp)
655+
562656
proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
563657
## Produces the Cartesian product of the array.
564658
## Every element of the result is a combination of one element from each seq in `x`,

tests/stdlib/talgorithm.nim

Lines changed: 158 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ discard """
44
'''
55
"""
66
#12928,10456
7-
import std/[sequtils, algorithm, json]
7+
8+
import std/[sequtils, algorithm, json, sugar]
89

910
proc test() =
1011
try:
@@ -114,3 +115,159 @@ block:
114115
doAssert binarySearch(moreData, 6) == -1
115116
doAssert binarySearch(moreData, 4711) == 4
116117
doAssert binarySearch(moreData, 4712) == -1
118+
119+
# merge
120+
proc main() =
121+
block:
122+
var x = @[1, 7, 8, 11, 21, 33, 45, 99]
123+
var y = @[6, 7, 9, 12, 57, 66]
124+
125+
var merged: seq[int]
126+
merged.merge(x, y)
127+
doAssert merged.isSorted
128+
doAssert merged == sorted(x & y)
129+
130+
block:
131+
var x = @[111, 88, 76, 56, 45, 31, 22, 19, 11, 3]
132+
var y = @[99, 85, 83, 82, 69, 64, 48, 42, 33, 31, 26, 13]
133+
134+
var merged: seq[int]
135+
merged.merge(x, y, (x, y) => -system.cmp(x, y))
136+
doAssert merged.isSorted((x, y) => -system.cmp(x, y))
137+
doAssert merged == sorted(x & y, SortOrder.Descending)
138+
139+
block:
140+
var x: seq[int] = @[]
141+
var y = @[1]
142+
143+
var merged: seq[int]
144+
merged.merge(x, y)
145+
doAssert merged.isSorted
146+
doAssert merged.isSorted(SortOrder.Descending)
147+
doAssert merged == @[1]
148+
149+
block:
150+
var x = [1, 3, 5, 5, 7]
151+
var y: seq[int] = @[]
152+
153+
var merged: seq[int]
154+
merged.merge(x, y)
155+
doAssert merged.isSorted
156+
doAssert merged == @x
157+
158+
block:
159+
var x = [1, 3, 5, 5, 7]
160+
var y: seq[int] = @[]
161+
162+
var merged: seq[int] = @[1, 2, 3, 5, 6, 56, 99, 2, 34]
163+
merged.merge(x, y)
164+
doAssert merged == @[1, 2, 3, 5, 6, 56, 99, 2, 34, 1, 3, 5, 5, 7]
165+
166+
167+
block:
168+
var x: array[0, int]
169+
var y = [1, 4, 6, 7, 9]
170+
171+
var merged: seq[int]
172+
merged.merge(x, y)
173+
doAssert merged.isSorted
174+
doAssert merged == @y
175+
176+
block:
177+
var x: array[0, int]
178+
var y: array[0, int]
179+
180+
var merged: seq[int]
181+
merged.merge(x, y)
182+
doAssert merged.isSorted
183+
doAssert merged.len == 0
184+
185+
block:
186+
var x: array[0, int]
187+
var y: array[0, int]
188+
189+
var merged: seq[int] = @[99, 99, 99]
190+
merged.setLen(0)
191+
merged.merge(x, y)
192+
doAssert merged.isSorted
193+
doAssert merged.len == 0
194+
195+
block:
196+
var x: seq[int]
197+
var y: seq[int]
198+
199+
var merged: seq[int]
200+
merged.merge(x, y)
201+
doAssert merged.isSorted
202+
doAssert merged.len == 0
203+
204+
block:
205+
type
206+
Record = object
207+
id: int
208+
209+
proc r(id: int): Record =
210+
Record(id: id)
211+
212+
proc cmp(x, y: Record): int =
213+
if x.id == y.id: return 0
214+
if x.id < y.id: return -1
215+
result = 1
216+
217+
var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)]
218+
var y = @[r(4), r(7), r(12), r(13), r(77), r(99)]
219+
220+
var merged: seq[Record] = @[]
221+
merged.merge(x, y, cmp)
222+
doAssert merged.isSorted(cmp)
223+
doAssert merged.len == 12
224+
225+
block:
226+
type
227+
Record = object
228+
id: int
229+
230+
proc r(id: int): Record =
231+
Record(id: id)
232+
233+
proc ascendingCmp(x, y: Record): int =
234+
if x.id == y.id: return 0
235+
if x.id < y.id: return -1
236+
result = 1
237+
238+
proc descendingCmp(x, y: Record): int =
239+
if x.id == y.id: return 0
240+
if x.id < y.id: return 1
241+
result = -1
242+
243+
var x = @[r(-12), r(1), r(3), r(8), r(13), r(88)]
244+
var y = @[r(4), r(7), r(12), r(13), r(77), r(99)]
245+
246+
var merged: seq[Record]
247+
merged.setLen(0)
248+
merged.merge(x, y, ascendingCmp)
249+
doAssert merged.isSorted(ascendingCmp)
250+
doAssert merged == sorted(x & y, ascendingCmp)
251+
252+
reverse(x)
253+
reverse(y)
254+
255+
merged.setLen(0)
256+
merged.merge(x, y, descendingCmp)
257+
doAssert merged.isSorted(descendingCmp)
258+
doAssert merged == sorted(x & y, ascendingCmp, SortOrder.Descending)
259+
260+
reverse(x)
261+
reverse(y)
262+
merged.setLen(0)
263+
merged.merge(x, y, proc (x, y: Record): int = -descendingCmp(x, y))
264+
doAssert merged.isSorted(proc (x, y: Record): int = -descendingCmp(x, y))
265+
doAssert merged == sorted(x & y, ascendingCmp)
266+
267+
268+
var x: seq[(int, int)]
269+
x.merge([(1,1)], [(1,2)], (a,b) => a[0] - b[0])
270+
doAssert x == @[(1, 1), (1, 2)]
271+
272+
static: main()
273+
main()

0 commit comments

Comments
 (0)