From 35fd1954d8d9e7ad1823d51887c3224f94d344ab Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Wed, 9 Aug 2023 16:53:55 +0200 Subject: [PATCH 01/17] change: use undefined in ListNode instead of null - BREAKING: Changes type of ListNode - ListNode has been moved to src/node.ts --- src/index.ts | 19 +------------------ src/node.ts | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 18 deletions(-) create mode 100644 src/node.ts diff --git a/src/index.ts b/src/index.ts index e5029de..6ee1ed3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,21 +1,4 @@ -class ListNode { - /** - * Next node in the linked list - */ - next: ListNode | null = null; - /** - * Previous node in the linked list - */ - prev: ListNode | null = null; - /** - * Current value of this node - */ - value: T; - - constructor(value: T) { - this.value = value; - } -} +import { ListNode } from "./node"; export type { ListNode }; diff --git a/src/node.ts b/src/node.ts new file mode 100644 index 0000000..187d7a9 --- /dev/null +++ b/src/node.ts @@ -0,0 +1,18 @@ +export class ListNode { + /** + * Next node in the linked list + */ + next?: ListNode; + /** + * Previous node in the linked list + */ + prev?: ListNode; + /** + * Current value of this node + */ + value: T; + + constructor(value: T) { + this.value = value; + } +} From 894d02628380f0c6d5c439778ea69875ba195807 Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Wed, 9 Aug 2023 16:59:45 +0200 Subject: [PATCH 02/17] change: also stop using null in List --- src/index.ts | 32 ++++++++++++++++---------------- tests/remove.test.ts | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/index.ts b/src/index.ts index 6ee1ed3..50ebdfa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,8 +13,8 @@ export type ListTest = ( ) => boolean; export class List { - #head: ListNode | null = null; - #tail: ListNode | null = null; + #head?: ListNode; + #tail?: ListNode; #length: number = 0; constructor(from?: Iterable) { @@ -99,7 +99,7 @@ export class List { */ push(value: T) { const node = new ListNode(value); - if (this.#tail == null) { + if (!this.#tail) { this.#head = node; } else { this.#tail.next = node; @@ -116,14 +116,14 @@ export class List { * @returns Value or `undefined` */ pop() { - if (this.#tail == null) return undefined; + if (!this.#tail) return; const node = this.#tail; const prev = node.prev; if (!prev) { - this.#head = null; + this.#head = undefined; } else { - prev.next = null; + prev.next = undefined; } this.#tail = prev; @@ -138,14 +138,14 @@ export class List { */ shift() { const node = this.#head; - if (!node) return undefined; + if (!node) return; const next = node.next; - node.next = null; + node.next = undefined; if (!next) { - this.#tail = null; + this.#tail = undefined; } else { - next.prev = null; + next.prev = undefined; } this.#head = next; @@ -179,9 +179,9 @@ export class List { * @returns `ListNode` or `undefined` */ getNode(n: number) { - if (n < 0 || n >= this.#length) return undefined; + if (n < 0 || n >= this.#length) return; const mid = this.#length / 2; - let curr: ListNode | null; + let curr: ListNode | undefined; if (n < mid) { curr = this.#head; @@ -197,7 +197,7 @@ export class List { } } - return curr || undefined; + return curr; } /** @@ -279,8 +279,8 @@ export class List { for (let i = 0; i < amount; i++) { if (!curr) return true; const { prev, next } = curr; - curr.next = null; - curr.prev = null; + curr.next = undefined; + curr.prev = undefined; this.#length--; if (prev) { @@ -692,7 +692,7 @@ export class List { (end ?? 0) < 0 ? Math.max(0, this.#length + (end ?? 0)) : end ?? this.#length; - let curr: ListNode | null | undefined = this.getNode(startAt); + let curr: ListNode | undefined = this.getNode(startAt); let index = startAt; while (curr && index < endAt) { diff --git a/tests/remove.test.ts b/tests/remove.test.ts index 64d2f11..782aae6 100644 --- a/tests/remove.test.ts +++ b/tests/remove.test.ts @@ -44,7 +44,7 @@ test("can remove from start of list", () => { assert.is(list.head, lorem[2], "updated head"); assert.is( list.getNode(0)?.prev, - null, + undefined, "head does not point back at removed node" ); assert.is(list.length, lorem.length - 2, "updated length"); @@ -58,7 +58,7 @@ test("can remove from end of list", () => { assert.is(list.tail, lorem[3], "updated tail"); assert.is( list.getNode(3)?.next, - null, + undefined, "tail does not point forward to removed node" ); assert.is(list.length, 4, "updated length"); From ff366c6c29db4c7f0a83c558bb8d688dbc651baa Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Wed, 9 Aug 2023 17:10:16 +0200 Subject: [PATCH 03/17] remove: deprecated fromArray method --- docs/static-methods.md | 8 -------- src/index.ts | 17 +---------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/docs/static-methods.md b/docs/static-methods.md index bd8cb87..bb4b956 100644 --- a/docs/static-methods.md +++ b/docs/static-methods.md @@ -1,13 +1,5 @@ # Static Methods -## `fromArray` - -Creates a new List from any Array. This method has been deprecated in v1.2.0 and will be removed in a future version. Use the new constructor instead (see [Creating a List](./README.md#creating-a-list))! - -```js -const list = List.fromArray([1, 2, 3]); -``` - ## `isList` Checks if an object (or any other value) is a List diff --git a/src/index.ts b/src/index.ts index 50ebdfa..0662653 100644 --- a/src/index.ts +++ b/src/index.ts @@ -45,21 +45,6 @@ export class List { this.#length = length; } - /** - * Creates new List from Array. This method has been deprecated in v1.2.0 and - * will be removed in a future version. Use the new constructor instead! - * @param arr Array to turn into List - * @returns List - * @deprecated - */ - static fromArray(arr: T[] | readonly T[]): List { - const list = new List(); - for (let i = 0; i < arr.length; i++) { - list.push(arr[i]); - } - return list; - } - /** * Checks if an object (or any other value) is a List * @param list Object that may be a list @@ -715,7 +700,7 @@ export class List { */ sort(callback?: (a: T, b: T) => number): List { const arr = this.toArray().sort(callback); - return List.fromArray(arr); + return new List(arr); } /** From af055524d08e731ddd61d41c965a9e57cfdc7e0e Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Wed, 22 Jan 2025 14:05:19 +0100 Subject: [PATCH 04/17] add: implement symbol iterator method --- src/index.ts | 31 ++++++++++++++++++++++++ tests/symbol-iterator.test.ts | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 tests/symbol-iterator.test.ts diff --git a/src/index.ts b/src/index.ts index 996ea47..81b07ee 100644 --- a/src/index.ts +++ b/src/index.ts @@ -732,4 +732,35 @@ export class List { toString() { return this.join(","); } + + *[Symbol.iterator]() { + const seenNodes = new Set>(); + let curr = this.#head; + let idx = 0; + + while (idx < this.length) { + if (curr) { + yield curr.value; + seenNodes.add(curr); + curr = curr.next; + idx++; + continue; + } + + if (idx >= this.length) return; + + // find current element assuming list got modified + let temp = this.#head; + let i = 0; + while (temp && i < idx) { + temp = temp.next; + i++; + } + + if (temp && i == idx) { + curr = temp; + continue; + } + } + } } diff --git a/tests/symbol-iterator.test.ts b/tests/symbol-iterator.test.ts new file mode 100644 index 0000000..f0e5017 --- /dev/null +++ b/tests/symbol-iterator.test.ts @@ -0,0 +1,45 @@ +import { test } from "uvu"; +import * as assert from "uvu/assert"; +import { List } from "../src"; + +test("it iterates over basic list", () => { + const list = new List([1, 2, 3, 4, 5, 6, 7, 8, 9]); + let i = 1; + for (const val of list) { + assert.is(val, i); + i++; + } +}); + +test("it continues to iterate after splice", () => { + const subjectArray = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]; + const subjectList = new List(subjectArray); + const outputArray = new Array(); + const outputList = new Array(); + + // array + for (const v of subjectArray) { + if (v == 4) subjectArray.splice(3, 3); + outputArray.push(v); + } + + // list + for (const v of subjectList) { + if (v == 4) subjectList.remove(3, 3); + outputList.push(v); + } + + try { + assert.equal(outputList, outputArray); + } catch (e) { + console.log({ + subjectArray: subjectArray.join(", "), + subjectList: subjectList.join(", "), + outputArray: outputArray.join(", "), + outputList: outputList.join(", ") + }); + throw e; + } +}); + +test.run(); From 2caf7b21f0e05d677c391dcb760efa774a20d23b Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Wed, 22 Jan 2025 14:08:25 +0100 Subject: [PATCH 05/17] change: remove entries method --- docs/methods/with-other-objects.md | 13 ------------- src/index.ts | 9 --------- 2 files changed, 22 deletions(-) diff --git a/docs/methods/with-other-objects.md b/docs/methods/with-other-objects.md index e081bdf..1eda6a4 100644 --- a/docs/methods/with-other-objects.md +++ b/docs/methods/with-other-objects.md @@ -53,16 +53,3 @@ const newList = list.concat(["baz", "foobar"]); list.toString(); // "foo,bar" newList.toString(); // "foo,bar,baz,foobar" ``` - -## `entries` - -Creates iterable of index, value pairs for every entry in the List. - -```js -const list = List.fromArray(["foo", "bar"]); -for (const [i, v] of list.entries()) { - console.log(`Index: ${i}, Value: ${v}`); - // Index: 0, Value: foo - // Index: 1, Value: bar -} -``` diff --git a/src/index.ts b/src/index.ts index 81b07ee..4590e1b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -437,15 +437,6 @@ export class List { return newList; } - /** - * Creates iterable of index, value pairs for every entry in the List. - * @returns IterableIterator - */ - // not tested as this is basically a proxy of the existing Array method - entries() { - return this.toArray().entries(); - } - /** * Checks if a test callback returns `true` for every value * @param callback Test callback From 32ea575b009b237dd993731449f22f683b5c8a10 Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Wed, 22 Jan 2025 14:11:57 +0100 Subject: [PATCH 06/17] refactor: make use of iteratior in toArray, clone and sort --- src/index.ts | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/index.ts b/src/index.ts index 4590e1b..f030eda 100644 --- a/src/index.ts +++ b/src/index.ts @@ -292,15 +292,7 @@ export class List { * @returns Array */ toArray(): T[] { - const arr = new Array(); - - let curr = this.#head; - while (curr) { - arr.push(curr.value); - curr = curr.next; - } - - return arr; + return Array.from(this); } /** @@ -413,12 +405,7 @@ export class List { * @returns new List */ clone(): List { - const newList = new List(); - let curr = this.#head; - while (curr) { - newList.push(curr.value); - curr = curr.next; - } + const newList = new List(this); return newList; } From 62f5aefeec131f1d7a28d11ea4fe2cafa9bd201f Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Wed, 22 Jan 2025 15:07:25 +0100 Subject: [PATCH 07/17] WIP: insertMany --- src/index.ts | 74 +++++++++++++++++++++++++++++++++++++--- tests/insertMany.test.ts | 15 ++++++++ 2 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 tests/insertMany.test.ts diff --git a/src/index.ts b/src/index.ts index f030eda..d23ee0d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,17 +22,17 @@ export class List { // spawn iterator const iterator = from[Symbol.iterator](); - let iterable = iterator.next(); - if (iterable.done) return; + let result = iterator.next(); + if (result.done) return; // prepare first node - const head = new ListNode(iterable.value); + const head = new ListNode(result.value); let prev = head; let length = 1; // iterate and create list - while (!(iterable = iterator.next()).done) { - const node = new ListNode(iterable.value); + while (!(result = iterator.next()).done) { + const node = new ListNode(result.value); node.prev = prev; prev.next = node; prev = node; @@ -400,6 +400,70 @@ export class List { return true; } + /** + * Insert any iterable into the current List at a given index + */ + insertMany(index: number, iterable: Iterable) { + if (index < 0 || index > this.length) return false; + + // at end of list + if (index == this.length) { + for (const val of iterable) { + this.push(val); + } + return true; + } + + //let prev: undefined | ListNode; + //let end: undefined | ListNode; + + // at start of list + if (index == 0) { + const iterator = iterable[Symbol.iterator](); + let result = iterator.next(); + if (result.done) return true; + + // prepare first node + const newHead = new ListNode(result.value); + let prev = newHead; + let length = 1; + + // iterate and create linked nodes + while (!(result = iterator.next()).done) { + const node = new ListNode(result.value); + node.prev = prev; + prev.next = node; + prev = node; + length++; + } + + // update list + this.#length += length; + if (this.#head) { + this.#head.prev = prev; + } + this.#head = newHead; + return true; + } + + // in middle of list + const start = this.getNode(index); + if (!start) return false; + let prev = start; + const end = start.next; + + for (const val of iterable) { + const node = new ListNode(val); + node.prev = prev; + prev.next = node; + prev = node; + this.#length++; + } + + prev.next = end; + return true; + } + /** * Creates a copy of the current List * @returns new List diff --git a/tests/insertMany.test.ts b/tests/insertMany.test.ts new file mode 100644 index 0000000..015c84a --- /dev/null +++ b/tests/insertMany.test.ts @@ -0,0 +1,15 @@ +import { test } from "uvu"; +import * as assert from "uvu/assert"; +import { List } from "../src"; +import { assertValidList } from "./utils/assertValidList"; +import { lorem, loremList } from "./utils/lorem"; + +test("it rejects negative index", () => { + const list = new List(); + assert.not( + list.insertMany(-7, loremList), + "reject negative index with false" + ); +}); + +test.run(); From 8b66403f41639060b07086027eb295c8d32803c0 Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:53:30 +0100 Subject: [PATCH 08/17] add: insertMany, deprecates insertList & insertArray --- src/index.ts | 81 ++++++++++++++++----------------------- tests/insertArray.test.ts | 67 -------------------------------- tests/insertList.test.ts | 70 --------------------------------- tests/insertMany.test.ts | 63 +++++++++++++++++++++++++++++- 4 files changed, 96 insertions(+), 185 deletions(-) delete mode 100644 tests/insertArray.test.ts delete mode 100644 tests/insertList.test.ts diff --git a/src/index.ts b/src/index.ts index d23ee0d..b79ddbb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -347,6 +347,7 @@ export class List { * Inserts all values from an Array into List at a given index and * returns `true`. If the index is outside of the range of the List * `false` is returned. + * @deprecated use insertMany instead * @param index Index at which to start insertion * @param arr Array of Values * @returns boolean @@ -374,6 +375,7 @@ export class List { * Inserts all values from another List into List at a given index and * returns `true`. If the index is outside of the range of the List `false` is * returned. + * @deprecated use insertMany instead * @param index Index at which to start insertion * @param list List from which to take values * @returns boolean @@ -400,67 +402,52 @@ export class List { return true; } - /** - * Insert any iterable into the current List at a given index - */ insertMany(index: number, iterable: Iterable) { + // TODO: could clamp index instead and return void? if (index < 0 || index > this.length) return false; + let prev: undefined | ListNode; // current node in loop + let next: undefined | ListNode; // node after inserted - // at end of list - if (index == this.length) { - for (const val of iterable) { - this.push(val); - } - return true; + // get nodes before and after inserted values if applicable + if (index == 0) { + prev = undefined; + next = this.#head; + this.#head = undefined; + } else if (index == this.length) { + prev = this.#tail; + next = undefined; + } else { + next = this.getNode(index); + prev = next?.prev; } - //let prev: undefined | ListNode; - //let end: undefined | ListNode; + // append to list + for (const val of iterable) { + const node = new ListNode(val); - // at start of list - if (index == 0) { - const iterator = iterable[Symbol.iterator](); - let result = iterator.next(); - if (result.done) return true; - - // prepare first node - const newHead = new ListNode(result.value); - let prev = newHead; - let length = 1; - - // iterate and create linked nodes - while (!(result = iterator.next()).done) { - const node = new ListNode(result.value); + // connect to previous element, if none this is the new first list node + if (prev) { node.prev = prev; prev.next = node; - prev = node; - length++; + } else { + this.#head = node; } - // update list - this.#length += length; - if (this.#head) { - this.#head.prev = prev; - } - this.#head = newHead; - return true; - } - - // in middle of list - const start = this.getNode(index); - if (!start) return false; - let prev = start; - const end = start.next; - - for (const val of iterable) { - const node = new ListNode(val); - node.prev = prev; - prev.next = node; prev = node; this.#length++; } - prev.next = end; + // connect to node after inserted values if applicable, + // or update tail otherwise as there are no values past this + if (prev) { + if (next) { + next.prev = prev; + prev.next = next; + } else { + this.#tail = prev; + } + } + return true; } diff --git a/tests/insertArray.test.ts b/tests/insertArray.test.ts deleted file mode 100644 index 307a391..0000000 --- a/tests/insertArray.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { test } from "uvu"; -import * as assert from "uvu/assert"; -import { List } from "../src"; -import { assertValidList } from "./utils/assertValidList"; -import { lorem } from "./utils/lorem"; - -test("rejects negative index", () => { - const list = new List(); - assert.not(list.insertArray(-7, lorem), "reject negative index with false"); -}); - -test("can insert at the end of the list", () => { - const list = new List(["first", "second"]); - assert.ok(list.insertArray(2, lorem), "inserted array at end of list"); - const expected = ["first", "second", ...lorem]; - for (let i = 0; i < expected.length; i++) { - assert.is( - list.get(i), - expected[i], - `inserted array at end of list (index: ${i})` - ); - } - assert.is(list.length, expected.length, "updated length after insertion"); - assert.is(list.tail, expected[expected.length - 1], "updated tail correctly"); - assertValidList(list); -}); - -test("can insert at the start of the list", () => { - const list = new List(["second-to-last", "last"]); - assert.ok(list.insertArray(0, lorem), "inserted array at start of list"); - const expected = [...lorem, "second-to-last", "last"]; - for (let i = 0; i < expected.length; i++) { - assert.is( - list.get(i), - expected[i], - `inserted array at start of list (index: ${i})` - ); - } - assert.is(list.length, expected.length, "updated length after insertion"); - assert.is(list.head, expected[0], "updated head correctly"); - assertValidList(list); -}); - -test("can insert in the middle of the list", () => { - const list = new List(["first", "second", "second-to-last", "last"]); - assert.ok(list.insertArray(2, lorem), "inserted array in middle of list"); - const expected = ["first", "second", ...lorem, "second-to-last", "last"]; - for (let i = 0; i < expected.length; i++) { - assert.is( - list.get(i), - expected[i], - `inserted array in middle of list (index: ${i})` - ); - } - assert.is(list.length, expected.length, "updated length after insertion"); - assertValidList(list); -}); - -test("rejects index that is too large", () => { - const list = new List(["first", "second", "second-to-last", "last"]); - assert.not( - list.insertArray(list.length + 1, lorem), - "reject index larger than length with false" - ); -}); - -test.run(); diff --git a/tests/insertList.test.ts b/tests/insertList.test.ts deleted file mode 100644 index 19fd2fc..0000000 --- a/tests/insertList.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { test } from "uvu"; -import * as assert from "uvu/assert"; -import { List } from "../src"; -import { assertValidList } from "./utils/assertValidList"; -import { lorem, loremList } from "./utils/lorem"; - -test("rejects negative index", () => { - const list = new List(); - assert.not( - list.insertList(-7, loremList), - "reject negative index with false" - ); -}); - -test("can insert at the end of the list", () => { - const list = new List(["first", "second"]); - assert.ok(list.insertList(2, loremList), "inserted list at the end"); - const expected = ["first", "second", ...lorem]; - for (let i = 0; i < expected.length; i++) { - assert.is( - list.get(i), - expected[i], - `inserted list at the end (index: ${i})` - ); - } - assert.is(list.length, expected.length, "updated length after insertion"); - assert.is(list.tail, expected[expected.length - 1], "updated tail correctly"); - assertValidList(list); -}); - -test("can insert at the start of the list", () => { - const list = new List(["second-to-last", "last"]); - assert.ok(list.insertList(0, loremList), "inserted at start of list"); - const expected = [...lorem, "second-to-last", "last"]; - for (let i = 0; i < expected.length; i++) { - assert.is( - list.get(i), - expected[i], - `inserted at start of list (index: ${i})` - ); - } - assert.is(list.length, expected.length, "updated length after insertion"); - assert.is(list.head, expected[0], "updated head correctly"); - assertValidList(list); -}); - -test("can insert in the middle of the list", () => { - const list = new List(["first", "second", "second-to-last", "last"]); - assert.ok(list.insertList(2, loremList), "inserted in middle of list"); - const expected = ["first", "second", ...lorem, "second-to-last", "last"]; - for (let i = 0; i < expected.length; i++) { - assert.is( - list.get(i), - expected[i], - `inserted in middle of list (index: ${i})` - ); - } - assert.is(list.length, expected.length, "updated length after insertion"); - assertValidList(list); -}); - -test("rejects index that is too large", () => { - const list = new List(["first", "second", "second-to-last", "last"]); - assert.not( - list.insertList(list.length + 1, loremList), - "reject index larger than length with false" - ); -}); - -test.run(); diff --git a/tests/insertMany.test.ts b/tests/insertMany.test.ts index 015c84a..636e531 100644 --- a/tests/insertMany.test.ts +++ b/tests/insertMany.test.ts @@ -4,7 +4,7 @@ import { List } from "../src"; import { assertValidList } from "./utils/assertValidList"; import { lorem, loremList } from "./utils/lorem"; -test("it rejects negative index", () => { +test("rejects negative index", () => { const list = new List(); assert.not( list.insertMany(-7, loremList), @@ -12,4 +12,65 @@ test("it rejects negative index", () => { ); }); +test("can insert at the end of the list", () => { + const list = new List(["first", "second"]); + assert.ok(list.insertMany(2, loremList), "inserted list at the end"); + const expected = ["first", "second", ...lorem]; + assertValidList(list); + + for (let i = 0; i < expected.length; i++) { + assert.is( + list.get(i), + expected[i], + `inserted list at the end (index: ${i})` + ); + } + assert.is(list.length, expected.length, "updated length after insertion"); + assert.is(list.tail, expected[expected.length - 1], "updated tail correctly"); +}); + +test("can insert at the start of the list", () => { + const list = new List(["second-to-last", "last"]); + assert.ok(list.insertMany(0, loremList), "inserted at start of list"); + const expected = [...lorem, "second-to-last", "last"]; + assertValidList(list); + + // TEMP: + //console.log({ list: list.toArray(), expected }); + + for (let i = 0; i < expected.length; i++) { + assert.is( + list.get(i), + expected[i], + `inserted at start of list (index: ${i})` + ); + } + assert.is(list.length, expected.length, "updated length after insertion"); + assert.is(list.head, expected[0], "updated head correctly"); +}); + +test("can insert in the middle of the list", () => { + const list = new List(["first", "second", "second-to-last", "last"]); + assert.ok(list.insertMany(2, loremList), "inserted in middle of list"); + const expected = ["first", "second", ...lorem, "second-to-last", "last"]; + assertValidList(list); + + for (let i = 0; i < expected.length; i++) { + assert.is( + list.get(i), + expected[i], + `inserted in middle of list (index: ${i})` + ); + } + assert.is(list.length, expected.length, "updated length after insertion"); +}); + +test("rejects index that is too large", () => { + const list = new List(["first", "second", "second-to-last", "last"]); + assert.not( + list.insertMany(list.length + 1, loremList), + "reject index larger than length with false" + ); +}); + test.run(); From 2ba8a559dcd106284a5c2868b9a6f901beedbe9c Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Fri, 24 Jan 2025 22:07:52 +0100 Subject: [PATCH 09/17] change: insertMany should clamp index --- src/index.ts | 16 +++++++--- tests/insertMany.test.ts | 66 ++++++++++++++++++++++++++-------------- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/src/index.ts b/src/index.ts index b79ddbb..25f7b18 100644 --- a/src/index.ts +++ b/src/index.ts @@ -402,18 +402,24 @@ export class List { return true; } + /** + * Inserts all values from another iterable (List, Array, etc.) into List at a + * given index. If the index is out of range values will be inserted at the + * start or end of the List as applicable. + * @param index + * @param iterable + * @returns `this` Reference + */ insertMany(index: number, iterable: Iterable) { - // TODO: could clamp index instead and return void? - if (index < 0 || index > this.length) return false; let prev: undefined | ListNode; // current node in loop let next: undefined | ListNode; // node after inserted // get nodes before and after inserted values if applicable - if (index == 0) { + if (index <= 0) { prev = undefined; next = this.#head; this.#head = undefined; - } else if (index == this.length) { + } else if (index >= this.length) { prev = this.#tail; next = undefined; } else { @@ -448,7 +454,7 @@ export class List { } } - return true; + return this; } /** diff --git a/tests/insertMany.test.ts b/tests/insertMany.test.ts index 636e531..a012297 100644 --- a/tests/insertMany.test.ts +++ b/tests/insertMany.test.ts @@ -4,18 +4,13 @@ import { List } from "../src"; import { assertValidList } from "./utils/assertValidList"; import { lorem, loremList } from "./utils/lorem"; -test("rejects negative index", () => { - const list = new List(); - assert.not( - list.insertMany(-7, loremList), - "reject negative index with false" - ); -}); +const elementsL = ["first", "second", "third"]; +const elementsR = ["second-to-last", "last"]; +const expected = elementsL.concat(elementsR); test("can insert at the end of the list", () => { - const list = new List(["first", "second"]); - assert.ok(list.insertMany(2, loremList), "inserted list at the end"); - const expected = ["first", "second", ...lorem]; + const list = new List(elementsL); + list.insertMany(3, elementsR); assertValidList(list); for (let i = 0; i < expected.length; i++) { @@ -25,19 +20,16 @@ test("can insert at the end of the list", () => { `inserted list at the end (index: ${i})` ); } + assert.is(list.length, expected.length, "updated length after insertion"); assert.is(list.tail, expected[expected.length - 1], "updated tail correctly"); }); test("can insert at the start of the list", () => { - const list = new List(["second-to-last", "last"]); - assert.ok(list.insertMany(0, loremList), "inserted at start of list"); - const expected = [...lorem, "second-to-last", "last"]; + const list = new List(elementsR); + list.insertMany(0, elementsL); assertValidList(list); - // TEMP: - //console.log({ list: list.toArray(), expected }); - for (let i = 0; i < expected.length; i++) { assert.is( list.get(i), @@ -45,13 +37,14 @@ test("can insert at the start of the list", () => { `inserted at start of list (index: ${i})` ); } + assert.is(list.length, expected.length, "updated length after insertion"); assert.is(list.head, expected[0], "updated head correctly"); }); test("can insert in the middle of the list", () => { const list = new List(["first", "second", "second-to-last", "last"]); - assert.ok(list.insertMany(2, loremList), "inserted in middle of list"); + list.insertMany(2, loremList); const expected = ["first", "second", ...lorem, "second-to-last", "last"]; assertValidList(list); @@ -62,15 +55,42 @@ test("can insert in the middle of the list", () => { `inserted in middle of list (index: ${i})` ); } + assert.is(list.length, expected.length, "updated length after insertion"); }); -test("rejects index that is too large", () => { - const list = new List(["first", "second", "second-to-last", "last"]); - assert.not( - list.insertMany(list.length + 1, loremList), - "reject index larger than length with false" - ); +test("inserts at end of list if index too large", () => { + const list = new List(elementsL); + list.insertMany(list.length + 1, elementsR); + assertValidList(list); + + for (let i = 0; i < expected.length; i++) { + assert.is( + list.get(i), + expected[i], + `inserted list at the end (index: ${i})` + ); + } + + assert.is(list.length, expected.length, "updated length after insertion"); + assert.is(list.tail, expected[expected.length - 1], "updated tail correctly"); +}); + +test("inserts at start of list if index too low", () => { + const list = new List(elementsR); + list.insertMany(-7, elementsL); + assertValidList(list); + + for (let i = 0; i < expected.length; i++) { + assert.is( + list.get(i), + expected[i], + `inserted at start of list (index: ${i})` + ); + } + + assert.is(list.length, expected.length, "updated length after insertion"); + assert.is(list.head, expected[0], "updated head correctly"); }); test.run(); From c1e18726b6e2566a02df1c28f0ed66156b283eee Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Fri, 24 Jan 2025 22:11:17 +0100 Subject: [PATCH 10/17] change: make getNode private --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 25f7b18..9e2c392 100644 --- a/src/index.ts +++ b/src/index.ts @@ -163,7 +163,7 @@ export class List { * @param n Index of the element * @returns `ListNode` or `undefined` */ - getNode(n: number) { + private getNode(n: number) { if (n < 0 || n >= this.#length) return; const mid = this.#length / 2; let curr: ListNode | undefined; From 2198163a0127a5fed18b8fddef4f6218c058b4d0 Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Fri, 24 Jan 2025 22:12:41 +0100 Subject: [PATCH 11/17] docs: remove getNode from docs, replace insertList and insertArray with insertMany --- docs/methods/adding-removing.md | 10 ---------- docs/methods/with-other-objects.md | 21 ++++----------------- 2 files changed, 4 insertions(+), 27 deletions(-) diff --git a/docs/methods/adding-removing.md b/docs/methods/adding-removing.md index 30bceb8..43d5cf0 100644 --- a/docs/methods/adding-removing.md +++ b/docs/methods/adding-removing.md @@ -46,16 +46,6 @@ list.unshift("ipsum").unshift("dolor"); list.toString(); // "dolor,ipsum,lorem" ``` -## `getNode` - -Gets `ListNode` at specific index. If the index is outside of the range of the List `undefined` is returned. - -```js -const list = new List(); -list.pop("lorem"); -list.getNode(0); // ListNode { value: "lorem" } -``` - ## `get` Gets value at specific index. If the index is outside of the range of the List `undefined` is returned. diff --git a/docs/methods/with-other-objects.md b/docs/methods/with-other-objects.md index 1eda6a4..a7d4d9e 100644 --- a/docs/methods/with-other-objects.md +++ b/docs/methods/with-other-objects.md @@ -10,29 +10,16 @@ list.push("ipsum").push("dolor").unshift("lorem"); const arr = list.toArray(); // ["lorem", "ipsum", "dolor"] ``` -## `insertArray` +## `insertMany` -Inserts all values from an Array into List at a given index and returns `true`. -If the index is outside of the range of the List `false` is returned. +Inserts all values from an Iterable into List at a given index. Further methods can be chained after this method. ```js -const list = List.fromArray([0, 1, 2]); -list.insertArray(1, [0.5, 0.75]); +const list = new List([0, 1, 2]); +list.insertMany(1, [0.5, 0.75]); list.join(", "); // "0, 0.5, 0.75, 1, 2" ``` -## `insertList` - -Inserts all values from another List into List at a given index and returns `true`. -If the index is outside of the range of the List `false` is returned. - -```js -const listA = List.fromArray([0, 1, 2]); -const listB = List.fromArray("foo".split("")); -listA.insertList(2, listB); -listA.toString(); // "0,1,f,o,o,2" -``` - ## `clone` Creates a copy of the current List From bc03b58b144c6727be7f931c7ed4c17efff10e6d Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Fri, 24 Jan 2025 22:13:59 +0100 Subject: [PATCH 12/17] docs: remove Planned Features section --- docs/README.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/README.md b/docs/README.md index 49f3742..5fb705b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -24,11 +24,3 @@ list.push("lorem"); - [Working with other Data objects](methods/with-other-objects.md) - [Searching and Filtering](methods/searching-filtering.md) - [Transforming Lists](methods/transforming-lists.md) - -## Planned Features: - -- Support for asynchronous callback functions -- New Methods: - - `findNode` - - `values` (similar to entries) -- constructor that takes any iterable (replaces `List.fromArray`) From 0f0cc27925b979bb8fa176155282ab2ca7258bf9 Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Fri, 24 Jan 2025 22:21:18 +0100 Subject: [PATCH 13/17] docs: replace all usage of from Array with constructor --- docs/methods/adding-removing.md | 8 ++++---- docs/methods/searching-filtering.md | 2 +- docs/methods/transforming-lists.md | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/methods/adding-removing.md b/docs/methods/adding-removing.md index 43d5cf0..d7e4628 100644 --- a/docs/methods/adding-removing.md +++ b/docs/methods/adding-removing.md @@ -16,7 +16,7 @@ list.toString(); // "lorem,ipsum,dolor" Removes the last element from the List and returns it. If the List is empty `undefined` is returned. ```js -const list = List.fromArray(["lorem", "ipsum"]); +const list = new List(["lorem", "ipsum"]); list.pop(); // "ipsum" list.pop(); // "lorem" @@ -28,7 +28,7 @@ list.pop(); // undefined Removes the first element from the List and returns it. If the List is empty `undefined` is returned. ```js -const list = List.fromArray(["lorem", "ipsum"]); +const list = new List(["lorem", "ipsum"]); list.shift(); // "lorem" list.shift(); // "ipsum" @@ -75,7 +75,7 @@ Inserts value at index and returns `true`. If the index is outside of the range If the index would correspond to the next new element this method acts as an alias to `push`. ```js -const list = List.fromArray(["lorem", "ipsum"]); +const list = new List(["lorem", "ipsum"]); list.insert(1, "foo"); list.insert(4, "bar"); list.toString(); // "lorem,foo,ipsum,bar" @@ -87,7 +87,7 @@ Removes one or more elements starting at a given index and returns `true`. If the index is outside the range of the List or a amount smaller than one is given `false` is returned. ```js -const list = List.fromArray("foobazzbar".split("")); +const list = new List("foobazzbar".split("")); list.remove(3, 4); list.join(""); // "foobar" ``` diff --git a/docs/methods/searching-filtering.md b/docs/methods/searching-filtering.md index aa4cb7f..f4245cb 100644 --- a/docs/methods/searching-filtering.md +++ b/docs/methods/searching-filtering.md @@ -46,7 +46,7 @@ list.some(v => v.endsWith("foo")); // false Creates new list with only the values that the test callback returns `true` for. ```js -const list = List.fromArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); +const list = new List([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); const filtered = list.filter(v => v % 2 == 0); filtered.toString(); // "0,2,4,6,8" ``` diff --git a/docs/methods/transforming-lists.md b/docs/methods/transforming-lists.md index 3fb2c1a..1cac23e 100644 --- a/docs/methods/transforming-lists.md +++ b/docs/methods/transforming-lists.md @@ -102,7 +102,7 @@ Creates a new List that contains a slice of value from the original List startin Values are copied to the new List, meaning that modifying either List will not manipulate the other! ```js -const list = List.fromArray(["foo", "bar", "baz", "foobar", "lorem", "ipsum"]); +const list = new List(["foo", "bar", "baz", "foobar", "lorem", "ipsum"]); list.slice(2, 5).toString(); // "baz,foobar,lorem" list.slice(-3, 6).toString(); // "foobar,lorem,ipsum" list.slice(1, -1).toString(); // "bar,baz,foobar,lorem" @@ -115,7 +115,7 @@ Creates a new List with all values sorted by a comparison callback function. The If no callback is passed values are sorted in ascending ASCII character order. ```js -const list = List.fromArray([0, 7, 11, 8, 9, 15, -3]); +const list = new List([0, 7, 11, 8, 9, 15, -3]); const sorted = list.sort((a, b) => a - b); sorted.toString(); // -3,0,7,8,9,11,15 ``` From 79cf5d2c61b81b23d3d5ef20c07cc7b2bf6aafe2 Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Fri, 24 Jan 2025 22:28:53 +0100 Subject: [PATCH 14/17] fix: use bracket notation to allow access to getNode in tests --- tests/getNode.test.ts | 11 ++++++----- tests/remove.test.ts | 13 +++++++------ tests/utils/assertValidList.ts | 14 +++++++++----- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/tests/getNode.test.ts b/tests/getNode.test.ts index 3463160..6e6701a 100644 --- a/tests/getNode.test.ts +++ b/tests/getNode.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/dot-notation */ import { test } from "uvu"; import * as assert from "uvu/assert"; import { List } from "../src"; @@ -5,26 +6,26 @@ import { lorem } from "./utils/lorem"; test("Gets undefined from empty list", () => { const list = new List(); - assert.is(list.getNode(0), undefined, "return undefined for empty list"); + assert.is(list["getNode"](0), undefined, "return undefined for empty list"); }); test("Gets undefined for numbers outside of List's range", () => { const list = new List(lorem); assert.is( - list.getNode(-1), + list["getNode"](-1), undefined, "reject negative number with undefined" ); assert.is( - list.getNode(7), + list["getNode"](7), undefined, "reject number equal to length with undefined" ); assert.is( - list.getNode(8), + list["getNode"](8), undefined, "reject number greater than length with undefined" ); @@ -35,7 +36,7 @@ test("Gets correct value for valid index", () => { for (let i = 0; i < lorem.length; i++) { assert.is( - list.getNode(i)?.value, + list["getNode"](i)?.value, lorem[i], `get Node from list for index ${i}` ); diff --git a/tests/remove.test.ts b/tests/remove.test.ts index 782aae6..c2be56d 100644 --- a/tests/remove.test.ts +++ b/tests/remove.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/dot-notation */ import { test } from "uvu"; import * as assert from "uvu/assert"; import { List } from "../src"; @@ -24,13 +25,13 @@ test("can remove item after head", () => { assert.is(list.head, "lorem", "head unchanged"); assert.is(list.get(1), lorem[2], "removed item at index 1"); assert.is( - list.getNode(1)?.prev, - list.getNode(0), + list["getNode"](1)?.prev, + list["getNode"](0), "new item at index 1 points back to head" ); assert.is( - list.getNode(0)?.next, - list.getNode(1), + list["getNode"](0)?.next, + list["getNode"](1), "head updated to point to new item at index 1" ); assert.is(list.length, lorem.length - 1, "updated length"); @@ -43,7 +44,7 @@ test("can remove from start of list", () => { assert.ok(list.remove(0, 2), "remove two items from start of the list"); assert.is(list.head, lorem[2], "updated head"); assert.is( - list.getNode(0)?.prev, + list["getNode"](0)?.prev, undefined, "head does not point back at removed node" ); @@ -57,7 +58,7 @@ test("can remove from end of list", () => { assert.ok(list.remove(4, 10), "remove all element starting with index 4"); assert.is(list.tail, lorem[3], "updated tail"); assert.is( - list.getNode(3)?.next, + list["getNode"](3)?.next, undefined, "tail does not point forward to removed node" ); diff --git a/tests/utils/assertValidList.ts b/tests/utils/assertValidList.ts index a082122..ed2597b 100644 --- a/tests/utils/assertValidList.ts +++ b/tests/utils/assertValidList.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/dot-notation */ import * as assert from "uvu/assert"; import type { List } from "../../src"; @@ -6,12 +7,12 @@ export function assertValidList(list: List) { case 0: { assert.is(list.head, undefined, "no head value for empty list"); assert.is(list.tail, undefined, "no tail value for empty list"); - assert.not(list.getNode(0), "no node returned for empty list"); + assert.not(list["getNode"](0), "no node returned for empty list"); return; } case 1: { - const head = list.getNode(0); + const head = list["getNode"](0); assert.ok(head, "find head node of list"); assert.not(head.next, "head node has no next node for length of 1"); assert.not(head.prev, "head node has no prev node"); @@ -27,7 +28,7 @@ export function assertValidList(list: List) { "head node has the same value as list.tail" ); - const next = list.getNode(1); + const next = list["getNode"](1); assert.not( next, "no node found at index 1 for lenght of 1 (should only have index of 0" @@ -37,7 +38,7 @@ export function assertValidList(list: List) { default: { // test head to tail - const head = list.getNode(0); + const head = list["getNode"](0); assert.ok(head, "find head node of list"); assert.not(head.prev, "head node has no prev node"); assert.is( @@ -63,7 +64,10 @@ export function assertValidList(list: List) { // gets returned by list.getNode and // has the same value as list.tail assert.not(prev.next, "final node has no next linked node"); - assert.ok(prev === list.getNode(idx - 1), "can find final node by index"); + assert.ok( + prev === list["getNode"](idx - 1), + "can find final node by index" + ); assert.is( prev.value, list.tail, From fef334e5294114c8e62e9d51a0aa0228867c0ffd Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Fri, 24 Jan 2025 22:35:45 +0100 Subject: [PATCH 15/17] remove: insertList and insertArray --- src/index.ts | 115 +----------------------------------------- tests/toArray.test.ts | 2 +- 2 files changed, 3 insertions(+), 114 deletions(-) diff --git a/src/index.ts b/src/index.ts index 9e2c392..67d3d95 100644 --- a/src/index.ts +++ b/src/index.ts @@ -295,113 +295,6 @@ export class List { return Array.from(this); } - /** - * Utility method for insertArray and insertList that connects a lose list - * of already connected nodes into the existing list at a given index - * @param index index at which to insert - * @param first first inserted node - * @param last last inserted node - * @returns void - */ - private connectLose(index: number, first: ListNode, last: ListNode) { - switch (index) { - case 0: { - const oldHead = this.#head; - if (oldHead) { - last.next = oldHead; - oldHead.prev = last; - } else { - this.#tail = last; - } - this.#head = first; - break; - } - - case this.length: { - const oldTail = this.#tail; - if (oldTail) { - oldTail.next = first; - first.prev = oldTail; - } else { - this.#head = first; - } - this.#tail = last; - break; - } - - default: { - const target = this.getNode(index); - if (!target) return false; - - const prev = target.prev; - first.prev = prev; - if (prev) prev.next = first; - - last.next = target; - target.prev = last; - } - } - } - - /** - * Inserts all values from an Array into List at a given index and - * returns `true`. If the index is outside of the range of the List - * `false` is returned. - * @deprecated use insertMany instead - * @param index Index at which to start insertion - * @param arr Array of Values - * @returns boolean - */ - insertArray(index: number, arr: T[] | readonly T[]): boolean { - if (index < 0 || index > this.length) return false; - if (arr.length < 1) return true; - - // create new list - const firstInserted = new ListNode(arr[0]); - let currentInserted = firstInserted; - for (let i = 1; i < arr.length; i++) { - const node = new ListNode(arr[i]); - currentInserted.next = node; - node.prev = currentInserted; - currentInserted = node; - } - - this.connectLose(index, firstInserted, currentInserted); - this.#length += arr.length; - return true; - } - - /** - * Inserts all values from another List into List at a given index and - * returns `true`. If the index is outside of the range of the List `false` is - * returned. - * @deprecated use insertMany instead - * @param index Index at which to start insertion - * @param list List from which to take values - * @returns boolean - */ - insertList(index: number, list: List): boolean { - if (index < 0 || index > this.length || !List.isList(list)) return false; - const listHead = list.getNode(0); - if (!listHead) return true; // list.length == 0 - - // create new list - const firstInserted = new ListNode(listHead.value); - let currentInserted = firstInserted; - let iter = listHead.next; - while (iter) { - const node = new ListNode(iter.value); - currentInserted.next = node; - node.prev = currentInserted; - currentInserted = node; - iter = iter.next; - } - - this.connectLose(index, firstInserted, currentInserted); - this.#length += list.length; - return true; - } - /** * Inserts all values from another iterable (List, Array, etc.) into List at a * given index. If the index is out of range values will be inserted at the @@ -471,13 +364,9 @@ export class List { * @param value List or Array of Values * @returns new List */ - concat(value: List | Array | readonly T[]): List { + concat(value: Iterable): List { const newList = this.clone(); - if (List.isList(value)) { - newList.insertList(newList.length, value); - } else { - newList.insertArray(newList.length, value); - } + newList.insertMany(newList.length, value); return newList; } diff --git a/tests/toArray.test.ts b/tests/toArray.test.ts index 7cfee09..a0ad46e 100644 --- a/tests/toArray.test.ts +++ b/tests/toArray.test.ts @@ -8,7 +8,7 @@ test("Can convert List to Array", () => { assert.equal(list.toArray(), [], "return empty array for empty list"); - list.insertArray(0, lorem); + list.insertMany(0, lorem); assert.equal(list.toArray(), lorem, "return equal array to input"); }); From 7e4f95bd5d6cb04353de07522d39164fdcfde4e7 Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Fri, 24 Jan 2025 23:20:39 +0100 Subject: [PATCH 16/17] add: test insertMany on empty list --- tests/insertMany.test.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/insertMany.test.ts b/tests/insertMany.test.ts index a012297..922667e 100644 --- a/tests/insertMany.test.ts +++ b/tests/insertMany.test.ts @@ -93,4 +93,22 @@ test("inserts at start of list if index too low", () => { assert.is(list.head, expected[0], "updated head correctly"); }); +test("inserts into empty list correctly", () => { + const list = new List(); + list.insertMany(0, expected); + assertValidList(list); + + for (let i = 0; i < expected.length; i++) { + assert.is( + list.get(i), + expected[i], + `inserted at start of list (index: ${i})` + ); + } + + assert.is(list.length, expected.length, "updated length after insertion"); + assert.is(list.head, expected[0], "updated head correctly"); + assert.is(list.tail, expected[expected.length - 1], "updated tail correctly"); +}); + test.run(); From 46a089f272aab10c87b06fce0496af3f89e3c4dc Mon Sep 17 00:00:00 2001 From: Mitsunee <19474909+Mitsunee@users.noreply.github.com> Date: Sat, 25 Jan 2025 14:39:58 +0100 Subject: [PATCH 17/17] docs: move insertMany to adding-removing.md --- docs/methods/adding-removing.md | 10 ++++++++++ docs/methods/with-other-objects.md | 10 ---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/methods/adding-removing.md b/docs/methods/adding-removing.md index d7e4628..8bafefa 100644 --- a/docs/methods/adding-removing.md +++ b/docs/methods/adding-removing.md @@ -91,3 +91,13 @@ const list = new List("foobazzbar".split("")); list.remove(3, 4); list.join(""); // "foobar" ``` + +## `insertMany` + +Inserts all values from an Iterable into List at a given index. Further methods can be chained after this method. + +```js +const list = new List([0, 1, 2]); +list.insertMany(1, [0.5, 0.75]); +list.join(", "); // "0, 0.5, 0.75, 1, 2" +``` diff --git a/docs/methods/with-other-objects.md b/docs/methods/with-other-objects.md index a7d4d9e..6b3bd59 100644 --- a/docs/methods/with-other-objects.md +++ b/docs/methods/with-other-objects.md @@ -10,16 +10,6 @@ list.push("ipsum").push("dolor").unshift("lorem"); const arr = list.toArray(); // ["lorem", "ipsum", "dolor"] ``` -## `insertMany` - -Inserts all values from an Iterable into List at a given index. Further methods can be chained after this method. - -```js -const list = new List([0, 1, 2]); -list.insertMany(1, [0.5, 0.75]); -list.join(", "); // "0, 0.5, 0.75, 1, 2" -``` - ## `clone` Creates a copy of the current List