Merge sorted arrays with ordering in some manner in TypeScript
2022-02-14
TypeScriptIn Rust, iterable objects have peek
method to get the next value without advancing the iterator.
Peekable in std::iter - Rust
This concept could be used to achieve the purpose.
In merging 2 arrays with giving a certain order, peek each of them and then compare them to determine which one go first.
My sample implementation of Peekable
is:
export const peekable = <T>(arr: T[]) => {
const iterator = arr[Symbol.iterator]()
let state = iterator.next()
const peek = (): IteratorResult<T, null> => state
type Next<T> = ReturnType<typeof peek> extends IteratorReturnResult<null> ? IteratorReturnResult<null> : IteratorYieldResult<T>
return {
peek: () => state,
next: (): Next<T> => {
const value = peek()
state = iterator.next()
return <Next<T>>value
},
}
}
Key takeaways are:
- In JavaScript,
Symbol.iterator
is to get an iterator over an object - Store the first element in
state
so thatpeek()
method can use the value without advancingiterator
. - Declare
Next<T>
type and castvalue
before returning it innext
so that the return type ofnext()
can correspond to whatpeek()
is going to return.- In other words, when
peek()
returnsIteratorReturnResult
which represents the end of the iterator, it's ensured thatnext()
returnsIteratorReturnResult
as well.
- In other words, when
Thanks to peekable
, it's easy to merge arrays with comparing thier first elements which is the purpose of this article.
// compFn(t, u): -1(t < u) | 0(t == u) | 1(t > u)
export const mergeArrays = <T, U>(ts: T[], us: U[], compFn: (t: T, u: U) => -1 | 0 | 1) => {
const tIterator = peekable(ts)
const uIterator = peekable(us)
const arr: (T | U)[] = []
while (true) {
const tPeek = tIterator.peek()
const uPeek = uIterator.peek()
if (tPeek.done && uPeek.done) {
break
}
if (tPeek.done) {
arr.push(uIterator.next().value)
} else if (uPeek.done) {
arr.push(tIterator.next().value)
} else {
if (compFn(tPeek.value, uPeek.value) >= 0) {
arr.push(tIterator.next().value)
} else {
arr.push(uIterator.next().value)
}
}
}
return arr
}
Thanks to the Next<T>
type restriction tIterator.next()
is ensured being IteratorYieldResult<T>
after guarding on tPeek.done
.
Besides, the second argument compFn
returns a number, which is following Java's Comparable interface that returns a number as the result of comparing 2 given objects.