Skip to content

Commit f45cda3

Browse files
committed
Add merge()
1 parent 4508333 commit f45cda3

3 files changed

Lines changed: 70 additions & 0 deletions

File tree

src/Sequence.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ import minWith from "./minWith";
6868
import dropWhile from "./dropWhile";
6969
import takeWhile from "./takeWhile";
7070
import asIterable from "./asIterable";
71+
import merge from "./merge";
7172

7273
/**
7374
* A Sequence accepts an iterator and provides a fluent functional API consisting
@@ -152,6 +153,7 @@ export default class Sequence<T> {
152153
minBy = minBy;
153154
minWith = minWith;
154155
asIterable = asIterable;
156+
merge = merge;
155157
}
156158

157159
export function sequenceOf<T>(...args: Array<T>): Sequence<T> {

src/merge.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import Sequence, {asSequence} from "./Sequence";
2+
3+
/**
4+
* Merges the elements of both sequences into a new sequence. Each element of this sequence is eventually replaced with
5+
* an element of the other sequence by comparing results of the given `selector` function. If no value is found in the other
6+
* sequence the element is retained. New elements of the other sequence are appended to the end of the new sequence or
7+
* prepended to the start of the new sequence, if `prependNewValues` is set to `true`.
8+
*
9+
* @param {Sequence<T>} other
10+
* @param {(value: T) => S} selector
11+
* @param prependNewValues
12+
* @returns {Sequence<T>}
13+
*/
14+
function merge<T, S>(this: Sequence<T>, other: Sequence<T> | Iterable<T>, selector: (value: T) => S, prependNewValues: boolean = false): Sequence<T> {
15+
let mergeValues = other instanceof Sequence
16+
? other.toArray()
17+
: asSequence(other).toArray();
18+
const leftValues = this.toArray();
19+
const result = leftValues.map(left => {
20+
const selected = selector(left);
21+
const right = asSequence(mergeValues)
22+
.find(it => selector(it) === selected);
23+
if (right != null) {
24+
mergeValues = mergeValues.filter(it => it !== right);
25+
return right;
26+
} else {
27+
return left;
28+
}
29+
});
30+
if (prependNewValues) {
31+
return asSequence([...mergeValues, ...result]);
32+
} else {
33+
return asSequence([...result, ...mergeValues]);
34+
}
35+
}
36+
37+
export default merge;

test/merge.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import {sequenceOf} from "../src/Sequence";
2+
3+
describe("merge", () => {
4+
it("should merge both sequences", () => {
5+
const result = sequenceOf({id: 1, val: "a"}, {id: 2, val: "b"}, {id: 3, val: "c"})
6+
.merge(sequenceOf({id: 2, val: "bb"}), it => it.id)
7+
.toArray();
8+
expect(result).toEqual([{id: 1, val: "a"}, {id: 2, val: "bb"}, {id: 3, val: "c"}]);
9+
});
10+
11+
it("should merge given array", () => {
12+
const result = sequenceOf({id: 1, val: "a"}, {id: 2, val: "b"}, {id: 3, val: "c"})
13+
.merge([{id: 2, val: "bb"}], it => it.id)
14+
.toArray();
15+
expect(result).toEqual([{id: 1, val: "a"}, {id: 2, val: "bb"}, {id: 3, val: "c"}]);
16+
});
17+
18+
it("should merge both sequences and append new values", () => {
19+
const result = sequenceOf({id: 1, val: "a"}, {id: 2, val: "b"}, {id: 3, val: "c"})
20+
.merge(sequenceOf({id: 2, val: "bb"}, {id: 4, val: "d"}), it => it.id)
21+
.toArray();
22+
expect(result).toEqual([{id: 1, val: "a"}, {id: 2, val: "bb"}, {id: 3, val: "c"}, {id: 4, val: "d"}]);
23+
});
24+
25+
it("should merge both sequences and prepend new values", () => {
26+
const result = sequenceOf({id: 1, val: "a"}, {id: 2, val: "b"}, {id: 3, val: "c"})
27+
.merge(sequenceOf({id: 2, val: "bb"}, {id: 4, val: "d"}), it => it.id, true)
28+
.toArray();
29+
expect(result).toEqual([{id: 4, val: "d"}, {id: 1, val: "a"}, {id: 2, val: "bb"}, {id: 3, val: "c"}]);
30+
});
31+
});

0 commit comments

Comments
 (0)