Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add merge to algorithm #404

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@

- `writeStackTrace` is available in JS backend now.

- Added `algorithm.merge`.

## Language changes

- `nimscript` now handles `except Exception as e`.
Expand Down
62 changes: 62 additions & 0 deletions lib/pure/algorithm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
## * `sequtils module<sequtils.html>`_ for working with the built-in seq type
## * `tables module<tables.html>`_ for sorting tables

import std/private/since

type
SortOrder* = enum
Descending, Ascending
Expand Down Expand Up @@ -556,6 +558,66 @@ 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.} = nil): 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`,
## 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
sizeX = x.len
sizeY = y.len

result = newSeq[T](sizeX + sizeY)
var cmp = cmp
if cmp == nil:
when compiles(system.cmp[T]):
cmp = system.cmp[T]
else:
doAssert false

var
ix = 0
iy = 0
i = 0

while true:
if ix == sizeX:
while iy < sizeY:
result[i] = y[iy]
inc i
inc iy
return

if iy == sizeY:
while ix < sizeX:
result[i] = x[ix]
inc i
inc ix
return

let itemX = x[ix]
let itemY = y[iy]

if cmp(itemX, itemY) > 0:
result[i] = itemY
inc iy
else:
result[i] = itemX
inc ix

inc i

proc product*[T](x: openArray[seq[T]]): seq[seq[T]] =
## Produces the Cartesian product of the array. Warning: complexity
## may explode.
Expand Down
79 changes: 79 additions & 0 deletions tests/stdlib/talgorithm.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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