Linked List (Doubly)

The @abp/utils package provides a useful data structure known as a doubly linked list. It is availabe in both Angular (via an import) and MVC (via abp.utils.common global object).

Briefly, a doubly linked list is a series of records (a.k.a. nodes) which has information on the previous node, the next node, and its own value (or data).

Getting Started

To create a doubly linked list, all you have to do is to create a new instance of it:

In Angular:

import { LinkedList } from '@abp/utils';

const list = new LinkedList();
JavaScript

In MVC:

var list = new abp.utils.common.LinkedList();
JavaScript

The constructor does not get any parameters.

Usage

How to Add New Nodes

There are several methods to create new nodes in a linked list and all of them are separately available as well as revealed by add and addMany methods.

addHead(value)

addHead(value: T): ListNode<T>
JavaScript

Adds a node with given value as the first node in list:

list.addHead('a');

// "a"

list.addHead('b');

// "b" <-> "a"

list.addHead('c');

// "c" <-> "b" <-> "a"
JavaScript

addManyHead(values)

addManyHead(values: T[]): ListNode<T>[]
JavaScript

Adds multiple nodes with given values as the first nodes in list:

list.addManyHead(['a', 'b', 'c']);

// "a" <-> "b" <-> "c"

list.addManyHead(['x', 'y', 'z']);

// "x" <-> "y" <-> "z" <-> "a" <-> "b" <-> "c"
JavaScript

addTail(value)

addTail(value: T): ListNode<T>
JavaScript

Adds a node with given value as the last node in list:

list.addTail('a');

// "a"

list.addTail('b');

// "a" <-> "b"

list.addTail('c');

// "a" <-> "b" <-> "c"
JavaScript

addManyTail(values)

addManyTail(values: T[]): ListNode<T>[]
JavaScript

Adds multiple nodes with given values as the last nodes in list:

list.addManyTail(['a', 'b', 'c']);

// "a" <-> "b" <-> "c"

list.addManyTail(['x', 'y', 'z']);

// "a" <-> "b" <-> "c" <-> "x" <-> "y" <-> "z"
JavaScript

addAfter(value, previousValue [, compareFn])

addAfter(value: T, previousValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>
JavaScript

Adds a node with given value after the first node that has the previous value:

list.addTail('a');
list.addTail('b');
list.addTail('b');
list.addTail('c');

// "a" <-> "b" <-> "b" <-> "c"

list.addAfter('x', 'b');

// "a" <-> "b" <-> "x" <-> "b" <-> "c"
JavaScript

You may pass a custom compare function to detect the searched value:

list.addTail({ x: 1 });
list.addTail({ x: 2 });
list.addTail({ x: 3 });

// {"x":1} <-> {"x":2} <-> {"x":3}

list.addAfter(
  { x: 0 },
  2,
  (value, searchedValue) => value.x === searchedValue
);

// {"x":1} <-> {"x":2} <-> {"x":0} <-> {"x":3}
JavaScript

The default compare function checks deep equality, so you will rarely need to pass that parameter.

addManyAfter(values, previousValue [, compareFn])

addManyAfter(values: T[], previousValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>[]
JavaScript

Adds multiple nodes with given values after the first node that has the previous value:

list.addManyTail(['a', 'b', 'b', 'c']);

// "a" <-> "b" <-> "b" <-> "c"

list.addManyAfter(['x', 'y'], 'b');

// "a" <-> "b" <-> "x" <-> "y" <-> "b" <-> "c"
JavaScript

You may pass a custom compare function to detect the searched value:

list.addManyTail([{ x: 1 },{ x: 2 },{ x: 3 }]);

// {"x":1} <-> {"x":2} <-> {"x":3}

list.addManyAfter(
  [{ x: 4 }, { x: 5 }],
  2,
  (value, searchedValue) => value.x === searchedValue
);

// {"x":1} <-> {"x":2} <-> {"x":4} <-> {"x":5} <-> {"x":3}
JavaScript

The default compare function checks deep equality, so you will rarely need to pass that parameter.

addBefore(value, nextValue [, compareFn])

addBefore(value: T, nextValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>
JavaScript

Adds a node with given value before the first node that has the next value:

list.addTail('a');
list.addTail('b');
list.addTail('b');
list.addTail('c');

// "a" <-> "b" <-> "b" <-> "c"

list.addBefore('x', 'b');

// "a" <-> "x" <-> "b" <-> "b" <-> "c"
JavaScript

You may pass a custom compare function to detect the searched value:

list.addTail({ x: 1 });
list.addTail({ x: 2 });
list.addTail({ x: 3 });

// {"x":1} <-> {"x":2} <-> {"x":3}

list.addBefore(
  { x: 0 },
  2,
  (value, searchedValue) => value.x === searchedValue
);

// {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":3}
JavaScript

The default compare function checks deep equality, so you will rarely need to pass that parameter.

addManyBefore(values, nextValue [, compareFn])

addManyBefore(values: T[], nextValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>[]
JavaScript

Adds multiple nodes with given values before the first node that has the next value:

list.addManyTail(['a', 'b', 'b', 'c']);

// "a" <-> "b" <-> "b" <-> "c"

list.addManyBefore(['x', 'y'], 'b');

// "a" <-> "x" <-> "y" <-> "b" <-> "b" <-> "c"
JavaScript

You may pass a custom compare function to detect the searched value:

list.addManyTail([{ x: 1 },{ x: 2 },{ x: 3 }]);

// {"x":1} <-> {"x":2} <-> {"x":3}

list.addManyBefore(
  [{ x: 4 }, { x: 5 }],
  2,
  (value, searchedValue) => value.x === searchedValue
);

// {"x":1} <-> {"x":4} <-> {"x":5} <-> {"x":2} <-> {"x":3}
JavaScript

The default compare function checks deep equality, so you will rarely need to pass that parameter.

addByIndex(value, position)

addByIndex(value: T, position: number): ListNode<T>
JavaScript

Adds a node with given value at the specified position in the list:

list.addTail('a');
list.addTail('b');
list.addTail('c');

// "a" <-> "b" <-> "c"

list.addByIndex('x', 2);

// "a" <-> "b" <-> "x" <-> "c"
JavaScript

It works with negative index too:

list.addTail('a');
list.addTail('b');
list.addTail('c');

// "a" <-> "b" <-> "c"

list.addByIndex('x', -1);

// "a" <-> "b" <-> "x" <-> "c"
JavaScript

addManyByIndex(values, position)

addManyByIndex(values: T[], position: number): ListNode<T>[]
JavaScript

Adds multiple nodes with given values at the specified position in the list:

list.addManyTail(['a', 'b', 'c']);

// "a" <-> "b" <-> "c"

list.addManyByIndex(['x', 'y'], 2);

// "a" <-> "b" <-> "x" <-> "y" <-> "c"
JavaScript

It works with negative index too:

list.addManyTail(['a', 'b', 'c']);

// "a" <-> "b" <-> "c"

list.addManyByIndex(['x', 'y'], -1);

// "a" <-> "b" <-> "x" <-> "y" <-> "c"
JavaScript

add(value).head()

add(value: T).head(): ListNode<T>
JavaScript

Adds a node with given value as the first node in list:

list.add('a').head();

// "a"

list.add('b').head();

// "b" <-> "a"

list.add('c').head();

// "c" <-> "b" <-> "a"
JavaScript

This is an alternative API for addHead.

add(value).tail()

add(value: T).tail(): ListNode<T>
JavaScript

Adds a node with given value as the last node in list:

list.add('a').tail();

// "a"

list.add('b').tail();

// "a" <-> "b"

list.add('c').tail();

// "a" <-> "b" <-> "c"
JavaScript

This is an alternative API for addTail.

add(value).after(previousValue [, compareFn])

add(value: T).after(previousValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>
JavaScript

Adds a node with given value after the first node that has the previous value:

list.add('a').tail();
list.add('b').tail();
list.add('b').tail();
list.add('c').tail();

// "a" <-> "b" <-> "b" <-> "c"

list.add('x').after('b');

// "a" <-> "b" <-> "x" <-> "b" <-> "c"
JavaScript

You may pass a custom compare function to detect the searched value:

list.add({ x: 1 }).tail();
list.add({ x: 2 }).tail();
list.add({ x: 3 }).tail();

// {"x":1} <-> {"x":2} <-> {"x":3}

list
  .add({ x: 0 })
  .after(2, (value, searchedValue) => value.x === searchedValue);

// {"x":1} <-> {"x":2} <-> {"x":0} <-> {"x":3}
JavaScript

This is an alternative API for addAfter.

The default compare function checks deep equality, so you will rarely need to pass that parameter.

add(value).before(nextValue [, compareFn])

add(value: T).before(nextValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>
JavaScript

Adds a node with given value before the first node that has the next value:

list.add('a').tail();
list.add('b').tail();
list.add('b').tail();
list.add('c').tail();

// "a" <-> "b" <-> "b" <-> "c"

list.add('x').before('b');

// "a" <-> "x" <-> "b" <-> "b" <-> "c"
JavaScript

You may pass a custom compare function to detect the searched value:

list.add({ x: 1 }).tail();
list.add({ x: 2 }).tail();
list.add({ x: 3 }).tail();

// {"x":1} <-> {"x":2} <-> {"x":3}

list
  .add({ x: 0 })
  .before(2, (value, searchedValue) => value.x === searchedValue);

// {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":3}
JavaScript

This is an alternative API for addBefore.

The default compare function checks deep equality, so you will rarely need to pass that parameter.

add(value).byIndex(position)

add(value: T).byIndex(position: number): ListNode<T>
JavaScript

Adds a node with given value at the specified position in the list:

list.add('a').tail();
list.add('b').tail();
list.add('c').tail();

// "a" <-> "b" <-> "c"

list.add('x').byIndex(2);

// "a" <-> "b" <-> "x" <-> "c"
JavaScript

It works with negative index too:

list.add('a').tail();
list.add('b').tail();
list.add('c').tail();

// "a" <-> "b" <-> "c"

list.add('x').byIndex(-1);

// "a" <-> "b" <-> "x" <-> "c"
JavaScript

This is an alternative API for addByIndex.

addMany(values).head()

addMany(values: T[]).head(): ListNode<T>[]
JavaScript

Adds multiple nodes with given values as the first nodes in list:

list.addMany(['a', 'b', 'c']).head();

// "a" <-> "b" <-> "c"

list.addMany(['x', 'y', 'z']).head();

// "x" <-> "y" <-> "z" <-> "a" <-> "b" <-> "c"
JavaScript

This is an alternative API for addManyHead.

addMany(values).tail()

addMany(values: T[]).tail(): ListNode<T>[]
JavaScript

Adds multiple nodes with given values as the last nodes in list:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.addMany(['x', 'y', 'z']).tail();

// "a" <-> "b" <-> "c" <-> "x" <-> "y" <-> "z"
JavaScript

This is an alternative API for addManyTail.

addMany(values).after(previousValue [, compareFn])

addMany(values: T[]).after(previousValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>[]
JavaScript

Adds multiple nodes with given values after the first node that has the previous value:

list.addMany(['a', 'b', 'b', 'c']).tail();

// "a" <-> "b" <-> "b" <-> "c"

list.addMany(['x', 'y']).after('b');

// "a" <-> "b" <-> "x" <-> "y" <-> "b" <-> "c"
JavaScript

You may pass a custom compare function to detect the searched value:

list.addMany([{ x: 1 }, { x: 2 }, { x: 3 }]).tail();

// {"x":1} <-> {"x":2} <-> {"x":3}

list
  .addMany([{ x: 4 }, { x: 5 }])
  .after(2, (value, searchedValue) => value.x === searchedValue);

// {"x":1} <-> {"x":2} <-> {"x":4} <-> {"x":5} <-> {"x":3}
JavaScript

This is an alternative API for addManyAfter.

The default compare function checks deep equality, so you will rarely need to pass that parameter.

addMany(values).before(nextValue [, compareFn])

addMany(values: T[]).before(nextValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>[]
JavaScript

Adds multiple nodes with given values before the first node that has the next value:

list.addMany(['a', 'b', 'b', 'c']).tail();

// "a" <-> "b" <-> "b" <-> "c"

list.addMany(['x', 'y']).before('b');

// "a" <-> "x" <-> "y" <-> "b" <-> "b" <-> "c"
JavaScript

You may pass a custom compare function to detect the searched value:

list.addMany([{ x: 1 }, { x: 2 }, { x: 3 }]).tail();

// {"x":1} <-> {"x":2} <-> {"x":3}

list
  .addMany([{ x: 4 }, { x: 5 }])
  .before(2, (value, searchedValue) => value.x === searchedValue);

// {"x":1} <-> {"x":4} <-> {"x":5} <-> {"x":2} <-> {"x":3}
JavaScript

This is an alternative API for addManyBefore.

The default compare function checks deep equality, so you will rarely need to pass that parameter.

addMany(values).byIndex(position)

addMany(values: T[]).byIndex(position: number): ListNode<T>[]
JavaScript

Adds multiple nodes with given values at the specified position in the list:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.addMany(['x', 'y']).byIndex(2);

// "a" <-> "b" <-> "x" <-> "y" <-> "c"
JavaScript

It works with negative index too:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.addMany(['x', 'y']).byIndex(-1);

// "a" <-> "b" <-> "x" <-> "y" <-> "c"
JavaScript

This is an alternative API for addManyByIndex.

How to Remove Nodes

There are a few methods to remove nodes from a linked list and all of them are separately available as well as revealed from a drop method.

dropHead()

dropHead(): ListNode<T> | undefined
JavaScript

Removes the first node from the list:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.dropHead();

// "b" <-> "c"
JavaScript

dropManyHead(count)

dropManyHead(count: number): ListNode<T>[]
JavaScript

Removes the first nodes from the list based on given count:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.dropManyHead(2);

// "c"
JavaScript

dropTail()

dropTail(): ListNode<T> | undefined
JavaScript

Removes the last node from the list:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.dropTail();

// "a" <-> "b"
JavaScript

dropManyTail(count)

dropManyTail(count: number): ListNode<T>[]
JavaScript

Removes the last nodes from the list based on given count:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.dropManyTail(2);

// "a"
JavaScript

dropByIndex(position)

dropByIndex(position: number): ListNode<T> | undefined
JavaScript

Removes the node with the specified position from the list:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.dropByIndex(1);

// "a" <-> "c"
JavaScript

It works with negative index too:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.dropByIndex(-2);

// "a" <-> "c"
JavaScript

dropManyByIndex(count, position)

dropManyByIndex(count: number, position: number): ListNode<T>[]
JavaScript

Removes the nodes starting from the specified position from the list based on given count:

list.addMany(['a', 'b', 'c', 'd']).tail();

// "a" <-> "b" <-> "c" <-> "d

list.dropManyByIndex(2, 1);

// "a" <-> "d"
JavaScript

It works with negative index too:

list.addMany(['a', 'b', 'c', 'd']).tail();

// "a" <-> "b" <-> "c" <-> "d

list.dropManyByIndex(2, -2);

// "a" <-> "d"
JavaScript

dropByValue(value [, compareFn])

dropByValue(value: T, compareFn?: ListComparisonFn<T>): ListNode<T> | undefined
JavaScript

Removes the first node with given value from the list:

list.addMany(['a', 'x', 'b', 'x', 'c']).tail();

// "a" <-> "x" <-> "b" <-> "x" <-> "c"

list.dropByValue('x');

// "a" <-> "b" <-> "x" <-> "c"
JavaScript

You may pass a custom compare function to detect the searched value:

list.addMany([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]).tail();

// {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3}

list.dropByValue(0, (value, searchedValue) => value.x === searchedValue);

// {"x":1} <-> {"x":2} <-> {"x":0} <-> {"x":3}
JavaScript

The default compare function checks deep equality, so you will rarely need to pass that parameter.

dropByValueAll(value [, compareFn])

dropByValueAll(value: T, compareFn?: ListComparisonFn<T>): ListNode<T>[]
JavaScript

Removes all nodes with given value from the list:

list.addMany(['a', 'x', 'b', 'x', 'c']).tail();

// "a" <-> "x" <-> "b" <-> "x" <-> "c"

list.dropByValueAll('x');

// "a" <-> "b" <-> "c"
JavaScript

You may pass a custom compare function to detect the searched value:

list.addMany([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]).tail();

// {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3}

list.dropByValue(0, (value, searchedValue) => value.x === searchedValue);

// {"x":1} <-> {"x":2} <-> {"x":3}
JavaScript

The default compare function checks deep equality, so you will rarely need to pass that parameter.

drop().head()

drop().head(): ListNode<T> | undefined
JavaScript

Removes the first node in list:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.drop().head();

// "b" <-> "c"
JavaScript

This is an alternative API for dropHead.

drop().tail()

drop().tail(): ListNode<T> | undefined
JavaScript

Removes the last node in list:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.drop().tail();

// "a" <-> "b"
JavaScript

This is an alternative API for dropTail.

drop().byIndex(position)

drop().byIndex(position: number): ListNode<T> | undefined
JavaScript

Removes the node with the specified position from the list:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.drop().byIndex(1);

// "a" <-> "c"
JavaScript

It works with negative index too:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.drop().byIndex(-2);

// "a" <-> "c"
JavaScript

This is an alternative API for dropByIndex.

drop().byValue(value [, compareFn])

drop().byValue(value: T, compareFn?: ListComparisonFn<T>): ListNode<T> | undefined
JavaScript

Removes the first node with given value from the list:

list.addMany(['a', 'x', 'b', 'x', 'c']).tail();

// "a" <-> "x" <-> "b" <-> "x" <-> "c"

list.drop().byValue('x');

// "a" <-> "b" <-> "x" <-> "c"
JavaScript

You may pass a custom compare function to detect the searched value:

list.addMany([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]).tail();

// {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3}

list
  .drop()
  .byValue(0, (value, searchedValue) => value.x === searchedValue);

// {"x":1} <-> {"x":2} <-> {"x":0} <-> {"x":3}
JavaScript

This is an alternative API for dropByValue.

The default compare function checks deep equality, so you will rarely need to pass that parameter.

drop().byValueAll(value [, compareFn])

drop().byValueAll(value: T, compareFn?: ListComparisonFn<T>): ListNode<T>[]
JavaScript

Removes all nodes with given value from the list:

list.addMany(['a', 'x', 'b', 'x', 'c']).tail();

// "a" <-> "x" <-> "b" <-> "x" <-> "c"

list.drop().byValueAll('x');

// "a" <-> "b" <-> "c"
JavaScript

You may pass a custom compare function to detect the searched value:

list.addMany([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]).tail();

// {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3}

list
  .drop()
  .byValueAll(0, (value, searchedValue) => value.x === searchedValue);

// {"x":1} <-> {"x":2} <-> {"x":3}
JavaScript

This is an alternative API for dropByValueAll.

The default compare function checks deep equality, so you will rarely need to pass that parameter.

dropMany(count).head()

dropMany(count: number).head(): ListNode<T>[]
JavaScript

Removes the first nodes from the list based on given count:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.dropMany(2).head();

// "c"
JavaScript

This is an alternative API for dropManyHead.

dropMany(count).tail()

dropMany(count: number).tail(): ListNode<T>[]
JavaScript

Removes the last nodes from the list based on given count:

list.addMany(['a', 'b', 'c']).tail();

// "a" <-> "b" <-> "c"

list.dropMany(2).tail();

// "a"
JavaScript

This is an alternative API for dropManyTail.

dropMany(count).byIndex(position)

dropMany(count: number).byIndex(position: number): ListNode<T>[]
JavaScript

Removes the nodes starting from the specified position from the list based on given count:

list.addMany(['a', 'b', 'c', 'd']).tail();

// "a" <-> "b" <-> "c" <-> "d

list.dropMany(2).byIndex(1);

// "a" <-> "d"
JavaScript

It works with negative index too:

list.addMany(['a', 'b', 'c', 'd']).tail();

// "a" <-> "b" <-> "c" <-> "d

list.dropMany(2).byIndex(-2);

// "a" <-> "d"
JavaScript

This is an alternative API for dropManyByIndex.

How to Find Nodes

There are a few methods to find specific nodes in a linked list.

head: ListNode<T> | undefined;
JavaScript

Refers to the first node in the list.

tail

tail: ListNode<T> | undefined;
JavaScript

Refers to the last node in the list.

length

length: number;
JavaScript

Is the total number of nodes in the list.

find(predicate)

find(predicate: ListIteratorFn<T>): ListNode<T> | undefined
JavaScript

Finds the first node from the list that matches the given predicate:

list.addManyTail(['a', 'b', 'b', 'c']);

// "a" <-> "b" <-> "b" <-> "c"

var found = list.find(node => node.value === 'b');

/*
found.value === "b"
found.previous.value === "a"
found.next.value === "b"
*/
JavaScript

findIndex(predicate)

findIndex(predicate: ListIteratorFn<T>): number
JavaScript

Finds the position of the first node from the list that matches the given predicate:

list.addManyTail(['a', 'b', 'b', 'c']);

// "a" <-> "b" <-> "b" <-> "c"

var i0 = list.findIndex(node => node.next && node.next.value === 'b');
var i1 = list.findIndex(node => node.value === 'b');
var i2 = list.findIndex(node => node.previous && node.previous.value === 'b');
var i3 = list.findIndex(node => node.value === 'x');

/*
i0 === 0
i1 === 1
i2 === 2
i3 === -1
*/
JavaScript

get(position)

get(position: number): ListNode<T> | undefined
JavaScript

Finds and returns the node with specific position in the list:

list.addManyTail(['a', 'b', 'c']);

// "a" <-> "b" <-> "c"

var found = list.get(1);

/*
found.value === "b"
found.previous.value === "a"
found.next.value === "c"
*/
JavaScript

indexOf(value [, compareFn])

indexOf(value: T, compareFn?: ListComparisonFn<T>): number
JavaScript

Finds the position of the first node from the list that has the given value:

list.addManyTail(['a', 'b', 'b', 'c']);

// "a" <-> "b" <-> "b" <-> "c"

var i0 = list.indexOf('a');
var i1 = list.indexOf('b');
var i2 = list.indexOf('c');
var i3 = list.indexOf('x');

/*
i0 === 0
i1 === 1
i2 === 3
i3 === -1
*/
JavaScript

You may pass a custom compare function to detect the searched value:

list.addManyTail([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]);

// {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3}

var i0 = indexOf(1, (value, searchedValue) => value.x === searchedValue);
var i1 = indexOf(2, (value, searchedValue) => value.x === searchedValue);
var i2 = indexOf(3, (value, searchedValue) => value.x === searchedValue);
var i3 = indexOf(0, (value, searchedValue) => value.x === searchedValue);
var i4 = indexOf(4, (value, searchedValue) => value.x === searchedValue);

/*
i0 === 0
i1 === 2
i2 === 4
i3 === 1
i4 === -1
*/
JavaScript

The default compare function checks deep equality, so you will rarely need to pass that parameter.

How to Check All Nodes

There are a few ways to iterate over or display a linked list.

forEach(iteratorFn)

forEach(iteratorFn: ListIteratorFn<T>): void
JavaScript

Runs a function on all nodes in a linked list from head to tail:

list.addManyTail(['a', 'b', 'c']);

// "a" <-> "b" <-> "c"

list.forEach((node, index) => console.log(node.value + index));

// 'a0'
// 'b1'
// 'c2'
JavaScript

*[Symbol.iterator]()

A linked list is iterable. In other words, you may use methods like for...of on it.

list.addManyTail(['a', 'b', 'c']);

// "a" <-> "b" <-> "c"

for(const node of list) { /* ES6 for...of statement */
  console.log(node.value);
}

// 'a'
// 'b'
// 'c'
JavaScript

toArray()

toArray(): T[]
JavaScript

Converts a linked list to an array of values:

list.addManyTail(['a', 'b', 'c']);

// "a" <-> "b" <-> "c"

var arr = list.toArray();

/*
arr === ['a', 'b', 'c']
*/
JavaScript

toNodeArray()

toNodeArray(): ListNode<T>[]
JavaScript

Converts a linked list to an array of nodes:

list.addManyTail(['a', 'b', 'c']);

// "a" <-> "b" <-> "c"

var arr = list.toNodeArray();

/*
arr[0].value === 'a'
arr[1].value === 'a'
arr[2].value === 'a'
*/
JavaScript

toString([mapperFn])

toString(mapperFn: ListMapperFn<T> = JSON.stringify): string
JavaScript

Converts a linked list to a string representation of nodes and their relations:

list.addManyTail(['a', 2, 'c', { k: 4, v: 'd' }]);

// "a" <-> 2 <-> "c" <-> {"k":4,"v":"d"}

var str = list.toString();

/*
str === '"a" <-> 2 <-> "c" <-> {"k":4,"v":"d"}'
*/
JavaScript

You may pass a custom mapper function to map values before stringifying them:

list.addMany([{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }, { x: 5 }]).tail();

// {"x":1} <-> {"x":2} <-> {"x":3} <-> {"x":4} <-> {"x":5}

var str = list.toString(value => value.x);

/*
str === '1 <-> 2 <-> 3 <-> 4 <-> 5'
*/
JavaScript

API

Classes

LinkedList

export class LinkedList<T = any> {

  // properties and methods are explained above

}
JavaScript

ListNode

export class ListNode<T = any> {
  next: ListNode | undefined;

  previous: ListNode | undefined;
  
  constructor(public readonly value: T) {}
}
JavaScript

ListNode is the node that is being stored in the LinkedList for every record.

  • value is the value stored in the node and is passed through the constructor.
  • next refers to the next node in the list.
  • previous refers to the previous node in the list.
list.addManyTail([ 0, 1, 2 ]);

console.log(
  list.head.value,                              // 0
  list.head.next.value,                         // 1
  list.head.next.next.value,                    // 2
  list.head.next.next.previous.value,           // 1
  list.head.next.next.previous.previous.value,  // 0
  list.tail.value,                              // 2
  list.tail.previous.value,                     // 1
  list.tail.previous.previous.value,            // 0
  list.tail.previous.previous.next.value,       // 1
  list.tail.previous.previous.next.next.value,  // 2
);
JavaScript

Types

ListMapperFn

type ListMapperFn<T = any> = (value: T) => any;
JavaScript

This function is used in toString method to map the node values before generating a string representation of the list.

ListComparisonFn

type ListComparisonFn<T = any> = (nodeValue: T, comparedValue: any) => boolean;
JavaScript

This function is used while adding, dropping, ang finding nodes based on a comparison value.

ListIteratorFn

type ListIteratorFn<T = any, R = boolean> = (
  node: ListNode<T>,
  index?: number,
  list?: LinkedList,
) => R;
JavaScript

This function is used while iterating over the list either to do something with each node or to find a node.

Was this page helpful?

Please make a selection.

To help us improve, please share your reason for the negative feedback in the field below.

Please enter a note.

Thank you for your valuable feedback!

Please note that although we cannot respond to feedback, our team will use your comments to improve the experience.

Community Talks

What’s New with .NET 9 & ABP 9?

21 Nov, 17:00
Online
Watch the Event
Mastering ABP Framework Book
Mastering ABP Framework

This book will help you gain a complete understanding of the framework and modern web application development techniques.

Learn More