Zero dependency Doubly Linked List class with a variety of utilities.
- Installation
- Usage
- LinkedList.static.constructor
- LinkedList.static.from
- LinkedList.prototype.head
- LinkedList.prototype.tail
- LinkedList.prototype.size
- LinkedList.prototype[Symbol.iterator]
- LinkedList.prototype.values
- LinkedList.prototype.keys
- LinkedList.prototype.entries
- LinkedList.prototype.push
- LinkedList.prototype.unshift
- LinkedList.prototype.shift
- LinkedList.prototype.pop
- LinkedList.prototype.insert
- LinkedList.prototype.remove
- LinkedList.prototype.clear
- LinkedList.prototype.replace
- LinkedList.prototype.find
- LinkedList.prototype.forEach
- LinkedList.prototype.map
- LinkedList.prototype.filter
- LinkedList.prototype.reduce
- LinkedList.prototype.some
- LinkedList.prototype.every
- LinkedList.prototype.reverse
- LinkedList.prototype.sort
- LinkedList.prototype.clone
- LinkedList.prototype.toArray
- LinkedList.prototype.toValuesArray
- LinkedList.prototype.toEntriesArray
- LinkedList.prototype.toKeysArray
- LinkedList.prototype.toMap
- Updating Dependencies
- Publishing
npm install @nkp/linked-list
yarn add @nkp/linked-list
pnpm add @nkp/linked-list
@nkp/linked-list
targets CommonJS and ES modules. To utilise ES modules consider using a bundler like webpack
or rollup
.
Creates a new LinkedList instance.
// interface
class LinkedList<T> {
// ...
/**
* Create a new LinkedList
*
* @param values initial values to hydrate
*/
constructor(values?: LinkedList<T> | T[] | Iterable<T> | null);
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList<number>([1, 2, 3]);
Creates a new LinkedList instance.
Alias for LinkedList.constructor.
// interface
class LinkedList<T> {
// ...
/**
* Create a new LinkedList
*
* @param values initial values to hydrate
* @returns LinkedList instance
*/
static from<T>(values?: LinkedList<T> | T[] | Iterable<T> | null): LinkedList<T>;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = LinkedList<number>.from([1, 2, 3]);
Returns the value at the head (front) of the LinkedList.
// interface
class LinkedList<T> {
// ...
/**
* Value at the head of the linked list, if it exists
*/
public get head(): undefined | T;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a' 'b', 'c']);
console.log(list.head); // 'a'
Returns the value at the tail (end) of the LinkedList.
// interface
class LinkedList<T> {
// ...
/**
* Value at the tail of the linked list, if it exists
*/
public get tail(): undefined | T {
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a' 'b', 'c']);
console.log(list.tail); // 'c'
Number of items in the linked list.
Similar to Array.prototype.length
.
// interface
class LinkedList<T> {
// ...
/**
* Number of items in the linked list
*/
public get size(): number;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a' 'b', 'c']);
console.log(list.size); // 3
Creates an iterator for the items in the LinkedList.
Fulfills the Iterator interface making the for..of
available to LinkedList instances.
// interface
class LinkedList<T> {
// ...
/**
* Create an Iterator for the LinkedList's values
*/
[Symbol.iterator](): IterableIterator<T>;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a' 'b', 'c']);
// [Symbol.iterator]() fulfills the interface for the
// for...of syntax
for (const item of list) {
console.log(item);
}
// 'a'
// 'b'
// 'c'
Push values to the end of the LinkedList.
Similar to Array.prototype.push
.
// interface
class LinkedList<T> {
// ...
/**
* Push values to the end of the LinkedList
*
* @param values values to push
* @returns the number of items inserted
*/
push(...values: T[]): number;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c']);
console.log(list.size); // 3
console.log(list.head); // 'a'
console.log(list.tail); // 'c'
// ['a', 'b', 'c', 'd', 'e', 'f']
list.push('c', 'd', 'e');
console.log(list.size); // 6
console.log(list.head); // 'a'
console.log(list.tail); // 'e'
Unshift values onto the start of the LinkedList.
Similar to Array.prototype.unshift
.
// interface
class LinkedList<T> {
// ...
/**
* Push values onto the start of the LinkedList
*
* @param values values to unshift
* @returns the number of items inserted
*/
unshift(...values: T[]): number;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b' ,'c']);
console.log(list.size); // 3
console.log(list.head); // 'a'
console.log(list.tail); // 'c'
// ['d', 'e', 'f', 'a', 'b', 'c']
list.unshift('d', 'e', 'f');
console.log(list.size); // 6
console.log(list.head); // 'd'
console.log(list.tail); // 'c'
Retrieve and remove the item at the head of the LinkedList if it exists.
// interface
class LinkedList<T> {
// ...
/**
* Retrieve and remove the first value from the LinkedList
*
* @returns the value if it exists
*/
shift(): undefined | T;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a' 'b', 'c']);
console.log(list.size); // 3
console.log(list.head); // 'a'
console.log(list.shift()); // 'a'
console.log(list.size); // 2
console.log(list.head); // 'b'
Retrieve and remove the item at the tail of the LinkedList if it exists.
// interface
class LinkedList<T> {
// ...
/**
* Retrieve and remove the last value from the LinkedList
*
* @returns the value if it exists
*/
pop(): undefined | T;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a' 'b', 'c']);
console.log(list.size); // 3
console.log(list.tail); // 'c'
console.log(list.pop()); // 'c'
console.log(list.size); // 2
console.log(list.head); // 'b'
Insert values into the desired index in the Linked List.
Items currently at and to the right of the index are shifted right.
Supports negative indexing.
// interface
class LinkedList<T> {
// ...
/**
* Insert values at the given index
*
* Supports negative indexing
*
* @param from first index to insert into
* @param values values to insert
* @returns the number of values inserted
*/
insert(from: number, ...values: T[]): number;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c',]);
// returns: 3
list.insert(1, 'd', 'e', 'f');
// ['a', 'd', 'e', 'f', 'b', 'c']
console.log(list.toArray());
Remove the given number of values from the desired index forwards.
Supports negative indexing.
Similar to Array.prototype.splice
.
// interface
class LinkedList<T> {
// ...
/**
* Remove values starting at the given index
*
* Supports negative indexing
*
* @param from
* @param deleteCount
*/
remove(from: number, deleteCount = 1): T[];
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c', 'd']);
// ['b', 'c']
list.remove(1, 2);
// ['a', 'd']
console.log(list.toArray());
Removes all items from the LinkedList.
// interface
class LinkedList<T> {
// ...
/**
* Remove all values from the LinkedList
*/
clear(): void;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c',]);
console.log(list.size); // 3
console.log(list.head); // 'a'
console.log(list.tail); // 'c'
list.clear();
console.log(list.size); // 0
console.log(list.head); // undefined
console.log(list.tail); // undefined
Find the value that causes the predicate function to return truthy, replace it with the replacer function and return the replacing value.
// interface
class LinkedList<T> {
// ...
/**
* Find the first item for whom the predicate function returns truthy
*
* replace its value with the result of the replacer function
*
* @param callbackfn function to deterermine if this is the value
* @param thisArg `this` value for callbackfn
* @param returns the replaced, if it was replaced
*/
replace<S extends T, V extends T>(
predicate: (value: T, index: number, obj: LinkedList<T>) => value is S,
replace: (value: S, index: number, obj: LinkedList<T>) => V,
thisPredicateArg?: any,
thisReplaceArg?: any,
): undefined | V;
replace<S extends T>(
predicate: (value: T, index: number, obj: LinkedList<T>) => value is S,
replace: (value: S, index: number, obj: LinkedList<T>) => T,
thisPredicateArg?: any,
thisReplaceArg?: any,
): undefined | T;
replace<V extends T>(
predicate: (value: T, index: number, obj: LinkedList<T>) => unknown,
replace: (value: T, index: number, obj: LinkedList<T>) => V,
thisPredicateArg?: any,
thisReplaceArg?: any,
): undefined | V;
replace(
predicate: (value: T, index: number, obj: LinkedList<T>) => unknown,
replace: (value: T, index: number, obj: LinkedList<T>) => T,
thisPredicateArg?: any,
thisReplaceArg?: any,
): undefined | T;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c',]);
// LinkedList [
// 'a'
// 'c'
// 'c'
// ]
const ret = list.replace(
// find
(value) => value === 'b',
// replace
(value) => 'c',
});
// 'c'
console.log(ret);
Find and return the first item for whom the predicate function returns truthy.
Similar to Array.prototype.find
.
// interface
class LinkedList<T> {
// ...
/**
* Find and return the first item for whom the predicate function
* returns truthy
*
* @param callbackfn function to deterermine if this is the value
* @param thisArg `this` value for callbackfn
* @param returns the item, if it was found
*/
find<S extends T>(
predicate: (value: T, index: number, obj: LinkedList<T>) => value is S,
thisArg?: any,
): S | undefined;
find(
predicate: (value: T, index: number, obj: LinkedList<T>) => unknown,
thisArg?: any,
): T | undefined;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c',]);
// 'b'
console.log(list.find((value, index) => index % 2 === 1));
Executes a callback function for each value in the LinkedList.
Similar to Array.prototype.forEach
.
// interface
class LinkedList<T> {
// ...
/**
* Execute a callbackfn for each value in the LinkedList
*
* @param callbackfn function to fire for each value
* @param thisArg `this` value for callbackfn
*/
forEach(callbackfn: (value: T, index: number, linkedList: this) => void, thisArg?: any): void;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c',]);
list.forEach((value, index) => {
console.log(`value: ${value}, index: ${index}`);
});
// value: a, index: 0
// value: b, index: 1
// value: c, index: 2
Executes a callback function for each value in the LinkedList to return a value that is used to hydrate a new LinkedList.
Similar to Array.prototype.map
.
// interface
class LinkedList<T> {
// ...
/**
* Transform the LinkedList using by calling a function on each of its values
*
* @param callbackfn function to tranasform each value
* @param thisArg `this` value for callbackfn
* @returns the transformed LinkedList
*/
map<U>(callbackfn: (value: T, index: number, linkedList: this) => U, thisArg?: any): LinkedList<U>;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c']);
// [97, 98, 99]
const transformed = list.map((str) => str.charCodeAt(0));
Executes a callback function for each value in the LinkedList to create a new LinkedList of the values whose callbacks returned truthy.
Similar to Array.prototype.filter
.
// interface
class LinkedList<T> {
// ...
/**
* Filter the LinkedList by calling a function to detemine whether each item
* should be kept
*
* @param callbackfn function to determine whether to keep each valuea
* @param thisArg `this` value for callbackfn
* @returns the filtered LinkedList
*/
filter<S extends T>(callbackfn: (value: T, index: number, linkedList: this) => value is S, thisArg?: any): LinkedList<S>;
filter(callbackfn: (value: T, index: number, linkedList: this) => boolean, thisArg?: any): LinkedList<T>;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c']);
// ['a', 'c']
const fitered = list.filter((str) => str !== 'b');
Executes a callback function for current accumulated value each value in the LinkedList to return a new accumulated value to be given to the next call.
Similar to Array.prototype.reduce
.
// interface
class LinkedList<T> {
// ...
/**
* Execute `callbackfn` for each item in the LinkedList and accumulate
* each returned value to pass into the next call to `callbakcfn`
*
* Returns the last output produced by `callbackfn`
*
* @param callbackfn function to produce the next accumulated vlaue
* @param initialValue initial accumulated value
* @param thisArg `this` value for callbackfn
* @returns result of executing `callbackfn` on each item in the
* linkedList
*/
reduce<U>(callbackfn: (accumulator: U, next: T, index: number, linkedList: this) => U, initialValue: U, thisArg?: any): U;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c',]);
// get the sum of the charcodes in the LinkedList
const out = list.reduce((sum, str) => acc + str.charCodeAt(0), 0);
console.log(294);
Create an iterator for the values in thet LinkedList.
Similar to Array.prototype.values
.
// interface
class LinkedList<T> {
// ...
/**
* Create an Iterator the LinkedList's values
*
* @returns Iterator of the values in the LinkedList
*/
values(): IterableIterator<T>;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c']);
for (const value of list.values()) {
console.log(value);
}
// 'a'
// 'b'
// 'c'
Create an iterator for the indeces in thet LinkedList.
Similar to Array.prototype.keys
.
// interface
class LinkedList<T> {
// ...
/**
* Create an Iterator the LinkedList's indeces
*
* @returns Iterator of the indeces in the LinkedList
*/
keys(): IterableIterator<number>;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c']);
for (const value of list.keys()) {
console.log(value);
}
// 0
// 1
// 2
Create an iterator for the index-value entries in the LinkedList.
Similar to Array.prototype.entries
.
// interface
class LinkedList<T> {
// ...
/**
* Create an Iterator for the LinkedList's index-value entries
*
* @returns Iterator of the index-value entries in the LinkedList
*/
entries(): IterableIterator<[number, T]>;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c']);
for (const value of list.entries()) {
console.log(value);
}
// [0, 'a']
// [1, 'b']
// [2, 'c']
Create a map from the index-value entries in the LinkedList.
// interface
class LinkedList<T> {
// ...
/**
* Create a Map of the LinkedList's index-value entries
*
* @returns Map of the index-value entries in the LinkedList
*/
toMap(): Map<number, T>;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c']);
// Map {
// 0 => 'a',
// 1 => 'b',
// 2 => 'c',
// }
console.log(list.toMap());
Create an Array from the index-value entries in the LinkedList.
// interface
class LinkedList<T> {
// ...
/**
* Create an Array of the LinkedList's entries
*
* @returns Array of index-value entries in the LinkedList
*/
toEntriesArray(): [number, T][];
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c']);
// [
// [0, 'a',],
// [1, 'b',],
// [2, 'c',],
// }
console.log(list.toEntriesArray());
Create an Array from the indeces in the LinkedList.
// interface
class LinkedList<T> {
// ...
/**
* Create an Array of the LinkedList's indeces
*
* @returns Array of indeces in the LinkedList
*/
toKeysArray(): number[];
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c']);
// [0, 1, 2]
console.log(list.toKeysArray());
Create an Array from the values in the LinkedList.
Alias for LinkedList.prototype.toArray.
// interface
class LinkedList<T> {
// ...
/**
* Create an Array of the LinkedList's values
*
* Alias for {@link LinkedList.toArray}
*
* @returns Array of values in the LinkedList
*/
toValuesArray(): T[];
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c']);
// ['a', 'b', 'c']
console.log(list.toValuesArray());
Create an Array from the values in the LinkedList.
// interface
class LinkedList<T> {
// ...
/**
* Create an Array of the LinkedList's values
*
* @returns Array of values in the LinkedList
*/
toArray(): T[];
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c']);
// ['a', 'b', 'c']
console.log(list.toArray());
Create a shallow copy of the LinkedList.
Clones the linked list and its internal items but does not clone the values.
// interface
class LinkedList<T> {
// ...
/**
* Create a shallow clone of the LinkedList
*/
clone(): LinkedList<T>;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList([1, 2, 3]);
const clone = list.clone();
// true
console.log(list !== clone);
// but all values are the same
const listIterator = list[Symbol.iterator]():
const cloneIterator = list[Symbol.iterator]():
// check list and clone values against each-other
const listResult = listIterator.next();
while (!listResult.done) {
const cloneResult = cloneIterator.next();
console.log(listResult.value === cloneResult.value);
listResult = listIterator.next();
}
// true
// true
// true
Create a new LinkedList with the source LinkedList's values in reverse order.
Similar to Array.prototype.reverse
but creates a new LinkedList instead of mutating the source LinkedList.
// interface
class LinkedList<T> {
// ...
/**
* Create a new LinkedList with this LinkedList's values in reverse order
*
* @returns LinkedList with values reversed
*/
reverse(): LinkedList<T>;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b', 'c']);
// LinkedList ['c', 'b', 'a' ]
const reversed = list.reverse();
// false
console.log(list === reversed);
Create a new LinkedList with the source LinkedList's values but sorted.
Similar to Array.prototype.sort
but creates a new LinkedList instead of mutating the source LinkedList.
Like Array.prototype.sort
, by default coerces values to strings and sorts by char codes.
// interface
class LinkedList<T> {
// ...
/**
* Create a new LinkedList with this LinkedList's values sorted
*
* @param compareFn returns sorting precedence of items
* @returns LinkedList with values sorted
*/
sort(compareFn?: (a: T, b: T) => number): LinkedList<T>;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const alphaList = new LinkedList(['c', 'a', 'b']);
// LinkedList ['a', 'b', 'c' ]
const alphaSorted = alphaList.sort();
const numericList = new LinkedList([3, 1, 2]);
// LinkedList [1, 2, 3]
const numericSortedAsc = numericList.sort((a, b) => a - b);
// LinkedList [3, 2, 1]
const numericSortedDesc = numericList.sort((a, b) => b - a);
Determine whether a predicate returns truthy for any value in the LinkedList.
Similar to Array.prototype.some
.
Exits early if a truthy value is found.
// interface
class LinkedList<T> {
// ...
/**
* Returns true if the predicate function returns true for any item in the
* LinkedList
*
* Otherwise returns false
*
* @param predicate boolean function to test against values
* @param thisArg `this` value for `predicate`
* @returns does the predicate return true for any item in the
* LinkedList?
*/
some(predicate: (value: T, index: number, list: LinkedList<T>) => boolean, thisArg?: any): boolean;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b' ,'c']);
// true
console.log(list.some((value) => value === 'b'));
// false
console.log(list.some((value) => value === 'B'));
Determine whether a predicate returns truthy for every value in the LinkedList.
Similar to Array.prototype.every
.
Exits early if a falsy value is found.
// interface
class LinkedList<T> {
// ...
/**
* Returns true if the predicate function returns true for every item in the
* LinkedList
*
* Otherwise returns false
*
* @param predicate boolean function to test against values
* @param thisArg `this` value for `predicate`
* @returns does the predicate return true for every item in the
* LinkedList?
*/
every<U extends T>(predicate: (value: T, index: number, list: LinkedList<T>) => value is U, thisArg?: any): this is LinkedList<U>;
every(predicate: (value: T, index: number, list: LinkedList<T>) => boolean, thisArg?: any): boolean;
// ...
}
// example
import { LinkedList } from '@nkp/linked-list';
const list = new LinkedList(['a', 'b' ,'c']);
// false
console.log(list.every((value) => value === 'b'));
// true
console.log(list.every((value) => typeof value === 'string'));
To update dependencies run one of
# if npm
# update package.json
npx npm-check-updates -u
# install
npm install
# if yarn
# update package.json
yarn create npm-check-updates -u
# install
yarn
# if pnpm
# update package.json
pnpx npm-check-updates -u
# install
pnpm install
To a release a new version:
- Update the version number in package.json
- Push the new version to the
master
branch on GitHub - Create a
new release
on GitHub for the latest version
This will trigger a GitHub action that tests and publishes the npm package.