Merge pull request #3582 from abpframework/docs/3575

Improved LinkedList Documentation
pull/3642/head
Mehmet Erim 6 years ago committed by GitHub
commit 523bc071ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,20 +2,29 @@
The core module provides a useful data structure known as a [doubly linked list](https://en.wikipedia.org/wiki/Doubly_linked_list). 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).
The @abp/utils package provides a useful data structure known as a [doubly linked list](https://en.wikipedia.org/wiki/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 import and create a new instance of it:
To create a doubly linked list, all you have to do is to create a new instance of it:
In Angular:
```js
import { LinkedList } from '@abp/ng.core';
import { LinkedList } from '@abp/utils';
const list = new LinkedList();
```
In MVC:
```js
var list = new abp.utils.common.LinkedList();
```
The constructor does not get any parameters.
@ -33,7 +42,7 @@ There are several methods to create new nodes in a linked list and all of them a
#### addHead(value)
```js
addHead(value: T): ListNode\<T\>
addHead(value: T): ListNode<T>
```
Adds a node with given value as the first node in list:
@ -57,7 +66,7 @@ list.addHead('c');
#### addManyHead(values)
```js
addManyHead(values: T\[\]): ListNode\<T\>\[\]
addManyHead(values: T[]): ListNode<T>[]
```
Adds multiple nodes with given values as the first nodes in list:
@ -77,7 +86,7 @@ list.addManyHead(['x', 'y', 'z']);
#### addTail(value)
```js
addTail(value: T): ListNode\<T\>
addTail(value: T): ListNode<T>
```
Adds a node with given value as the last node in list:
@ -101,7 +110,7 @@ list.addTail('c');
#### addManyTail(values)
```js
addManyTail(values: T\[\]): ListNode\<T\>\[\]
addManyTail(values: T[]): ListNode<T>[]
```
Adds multiple nodes with given values as the last nodes in list:
@ -118,10 +127,10 @@ list.addManyTail(['x', 'y', 'z']);
#### addAfter(value, previousValue, compareFn)
#### addAfter(value, previousValue [, compareFn])
```js
addAfter(value: T, previousValue: T, compareFn = compare): ListNode\<T\>
addAfter(value: T, previousValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>
```
Adds a node with given value after the first node that has the previous value:
@ -165,10 +174,10 @@ list.addAfter(
#### addManyAfter(values, previousValue, compareFn)
#### addManyAfter(values, previousValue [, compareFn])
```js
addManyAfter(values: T\[\], previousValue: T, compareFn = compare): ListNode\<T\>\[\]
addManyAfter(values: T[], previousValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>[]
```
Adds multiple nodes with given values after the first node that has the previous value:
@ -207,10 +216,10 @@ list.addManyAfter(
#### addBefore(value, nextValue, compareFn)
#### addBefore(value, nextValue [, compareFn])
```js
addBefore(value: T, nextValue: T, compareFn = compare): ListNode\<T\>
addBefore(value: T, nextValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>
```
Adds a node with given value before the first node that has the next value:
@ -254,10 +263,10 @@ list.addBefore(
#### addManyBefore(values, nextValue, compareFn)
#### addManyBefore(values, nextValue [, compareFn])
```js
addManyBefore(values: T\[\], nextValue: T, compareFn = compare): ListNode\<T\>\[\]
addManyBefore(values: T[], nextValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>[]
```
Adds multiple nodes with given values before the first node that has the next value:
@ -299,7 +308,7 @@ list.addManyBefore(
#### addByIndex(value, position)
```js
addByIndex(value: T, position: number): ListNode\<T\>
addByIndex(value: T, position: number): ListNode<T>
```
Adds a node with given value at the specified position in the list:
@ -337,7 +346,7 @@ list.addByIndex('x', -1);
#### addManyByIndex(values, position)
```js
addManyByIndex(values: T\[\], position: number): ListNode\<T\>\[\]
addManyByIndex(values: T[], position: number): ListNode<T>[]
```
Adds multiple nodes with given values at the specified position in the list:
@ -371,7 +380,7 @@ list.addManyByIndex(['x', 'y'], -1);
#### add(value).head()
```js
add(value: T).head(): ListNode\<T\>
add(value: T).head(): ListNode<T>
```
Adds a node with given value as the first node in list:
@ -399,7 +408,7 @@ list.add('c').head();
#### add(value).tail()
```js
add(value: T).tail(): ListNode\<T\>
add(value: T).tail(): ListNode<T>
```
Adds a node with given value as the last node in list:
@ -424,10 +433,10 @@ list.add('c').tail();
#### add(value).after(previousValue, compareFn)
#### add(value).after(previousValue [, compareFn])
```js
add(value: T).after(previousValue: T, compareFn = compare): ListNode\<T\>
add(value: T).after(previousValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>
```
Adds a node with given value after the first node that has the previous value:
@ -471,10 +480,10 @@ list
#### add(value).before(nextValue, compareFn)
#### add(value).before(nextValue [, compareFn])
```js
add(value: T).before(nextValue: T, compareFn = compare): ListNode\<T\>
add(value: T).before(nextValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>
```
Adds a node with given value before the first node that has the next value:
@ -521,7 +530,7 @@ list
#### add(value).byIndex(position)
```js
add(value: T).byIndex(position: number): ListNode\<T\>
add(value: T).byIndex(position: number): ListNode<T>
```
Adds a node with given value at the specified position in the list:
@ -563,7 +572,7 @@ list.add('x').byIndex(-1);
#### addMany(values).head()
```js
addMany(values: T\[\]).head(): ListNode\<T\>\[\]
addMany(values: T[]).head(): ListNode<T>[]
```
Adds multiple nodes with given values as the first nodes in list:
@ -587,7 +596,7 @@ list.addMany(['x', 'y', 'z']).head();
#### addMany(values).tail()
```js
addMany(values: T\[\]).tail(): ListNode\<T\>\[\]
addMany(values: T[]).tail(): ListNode<T>[]
```
Adds multiple nodes with given values as the last nodes in list:
@ -608,10 +617,10 @@ list.addMany(['x', 'y', 'z']).tail();
#### addMany(values).after(previousValue, compareFn)
#### addMany(values).after(previousValue [, compareFn])
```js
addMany(values: T\[\]).after(previousValue: T, compareFn = compare): ListNode\<T\>\[\]
addMany(values: T[]).after(previousValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>[]
```
Adds multiple nodes with given values after the first node that has the previous value:
@ -650,10 +659,10 @@ list
#### addMany(values).before(nextValue, compareFn)
#### addMany(values).before(nextValue [, compareFn])
```js
addMany(values: T\[\]).before(nextValue: T, compareFn = compare): ListNode\<T\>\[\]
addMany(values: T[]).before(nextValue: T, compareFn?: ListComparisonFn<T>): ListNode<T>[]
```
Adds multiple nodes with given values before the first node that has the next value:
@ -695,7 +704,7 @@ list
#### addMany(values).byIndex(position)
```js
addMany(values: T\[\]).byIndex(position: number): ListNode\<T\>\[\]
addMany(values: T[]).byIndex(position: number): ListNode<T>[]
```
Adds multiple nodes with given values at the specified position in the list:
@ -739,7 +748,7 @@ There are a few methods to remove nodes from a linked list and all of them are s
#### dropHead()
```js
dropHead(): ListNode\<T\> | undefined
dropHead(): ListNode<T> | undefined
```
Removes the first node from the list:
@ -759,7 +768,7 @@ list.dropHead();
#### dropManyHead(count)
```js
dropManyHead(count: number): ListNode\<T\>\[\]
dropManyHead(count: number): ListNode<T>[]
```
Removes the first nodes from the list based on given count:
@ -779,7 +788,7 @@ list.dropManyHead(2);
#### dropTail()
```js
dropTail(): ListNode\<T\> | undefined
dropTail(): ListNode<T> | undefined
```
Removes the last node from the list:
@ -799,7 +808,7 @@ list.dropTail();
#### dropManyTail(count)
```js
dropManyTail(count: number): ListNode\<T\>\[\]
dropManyTail(count: number): ListNode<T>[]
```
Removes the last nodes from the list based on given count:
@ -819,7 +828,7 @@ list.dropManyTail(2);
#### dropByIndex(position)
```js
dropByIndex(position: number): ListNode\<T\> | undefined
dropByIndex(position: number): ListNode<T> | undefined
```
Removes the node with the specified position from the list:
@ -853,7 +862,7 @@ list.dropByIndex(-2);
#### dropManyByIndex(count, position)
```js
dropManyByIndex(count: number, position: number): ListNode\<T\>\[\]
dropManyByIndex(count: number, position: number): ListNode<T>[]
```
Removes the nodes starting from the specified position from the list based on given count:
@ -884,10 +893,10 @@ list.dropManyByIndex(2, -2);
#### dropByValue(value, compareFn)
#### dropByValue(value [, compareFn])
```js
dropByValue(value: T, compareFn = compare): ListNode\<T\> | undefined
dropByValue(value: T, compareFn?: ListComparisonFn<T>): ListNode<T> | undefined
```
Removes the first node with given value from the list:
@ -922,10 +931,10 @@ list.dropByValue(0, (value, searchedValue) => value.x === searchedValue);
#### dropByValueAll(value, compareFn)
#### dropByValueAll(value [, compareFn])
```js
dropByValueAll(value: T, compareFn = compare): ListNode\<T\>\[\]
dropByValueAll(value: T, compareFn?: ListComparisonFn<T>): ListNode<T>[]
```
Removes all nodes with given value from the list:
@ -963,7 +972,7 @@ list.dropByValue(0, (value, searchedValue) => value.x === searchedValue);
#### drop().head()
```js
drop().head(): ListNode\<T\> | undefined
drop().head(): ListNode<T> | undefined
```
Removes the first node in list:
@ -987,7 +996,7 @@ list.drop().head();
#### drop().tail()
```js
drop().tail(): ListNode\<T\> | undefined
drop().tail(): ListNode<T> | undefined
```
Removes the last node in list:
@ -1011,7 +1020,7 @@ list.drop().tail();
#### drop().byIndex(position)
```js
drop().byIndex(position: number): ListNode\<T\> | undefined
drop().byIndex(position: number): ListNode<T> | undefined
```
Removes the node with the specified position from the list:
@ -1046,10 +1055,10 @@ list.drop().byIndex(-2);
#### drop().byValue(value, compareFn)
#### drop().byValue(value [, compareFn])
```js
drop().byValue(value: T, compareFn = compare): ListNode\<T\> | undefined
drop().byValue(value: T, compareFn?: ListComparisonFn<T>): ListNode<T> | undefined
```
Removes the first node with given value from the list:
@ -1088,10 +1097,10 @@ list
#### drop().byValueAll(value, compareFn)
#### drop().byValueAll(value [, compareFn])
```js
drop().byValueAll(value: T, compareFn = compare): ListNode\<T\>\[\]
drop().byValueAll(value: T, compareFn?: ListComparisonFn<T>): ListNode<T>[]
```
Removes all nodes with given value from the list:
@ -1133,7 +1142,7 @@ list
#### dropMany(count).head()
```js
dropMany(count: number).head(): ListNode\<T\>\[\]
dropMany(count: number).head(): ListNode<T>[]
```
Removes the first nodes from the list based on given count:
@ -1157,7 +1166,7 @@ list.dropMany(2).head();
#### dropMany(count).tail()
```js
dropMany(count: number).tail(): ListNode\<T\>\[\]
dropMany(count: number).tail(): ListNode<T>[]
```
Removes the last nodes from the list based on given count:
@ -1181,7 +1190,7 @@ list.dropMany(2).tail();
#### dropMany(count).byIndex(position)
```js
dropMany(count: number).byIndex(position: number): ListNode\<T\>\[\]
dropMany(count: number).byIndex(position: number): ListNode<T>[]
```
Removes the nodes starting from the specified position from the list based on given count:
@ -1222,10 +1231,40 @@ There are a few methods to find specific nodes in a linked list.
#### head
```js
head: ListNode<T> | undefined;
```
Refers to the first node in the list.
#### tail
```js
tail: ListNode<T> | undefined;
```
Refers to the last node in the list.
#### length
```js
length: number;
```
Is the total number of nodes in the list.
#### find(predicate)
```js
find(predicate: ListIteratorFunction\<T\>): ListNode\<T\> | undefined
find(predicate: ListIteratorFn<T>): ListNode<T> | undefined
```
Finds the first node from the list that matches the given predicate:
@ -1235,7 +1274,7 @@ list.addTailMany(['a', 'b', 'b', 'c']);
// "a" <-> "b" <-> "b" <-> "c"
const found = list.find(node => node.value === 'b');
var found = list.find(node => node.value === 'b');
/*
found.value === "b"
@ -1249,7 +1288,7 @@ found.next.value === "b"
#### findIndex(predicate)
```js
findIndex(predicate: ListIteratorFunction\<T\>): number
findIndex(predicate: ListIteratorFn<T>): number
```
Finds the position of the first node from the list that matches the given predicate:
@ -1259,10 +1298,10 @@ list.addTailMany(['a', 'b', 'b', 'c']);
// "a" <-> "b" <-> "b" <-> "c"
const i0 = list.findIndex(node => node.next && node.next.value === 'b');
const i1 = list.findIndex(node => node.value === 'b');
const i2 = list.findIndex(node => node.previous && node.previous.value === 'b');
const i3 = list.findIndex(node => node.value === 'x');
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
@ -1277,7 +1316,7 @@ i3 === -1
#### get(position)
```js
get(position: number): ListNode\<T\> | undefined
get(position: number): ListNode<T> | undefined
```
Finds and returns the node with specific position in the list:
@ -1287,7 +1326,7 @@ list.addTailMany(['a', 'b', 'c']);
// "a" <-> "b" <-> "c"
const found = list.get(1);
var found = list.get(1);
/*
found.value === "b"
@ -1298,10 +1337,10 @@ found.next.value === "c"
#### indexOf(value, compareFn)
#### indexOf(value [, compareFn])
```js
indexOf(value: T, compareFn = compare): number
indexOf(value: T, compareFn?: ListComparisonFn<T>): number
```
Finds the position of the first node from the list that has the given value:
@ -1311,10 +1350,10 @@ list.addTailMany(['a', 'b', 'b', 'c']);
// "a" <-> "b" <-> "b" <-> "c"
const i0 = list.indexOf('a');
const i1 = list.indexOf('b');
const i2 = list.indexOf('c');
const i3 = list.indexOf('x');
var i0 = list.indexOf('a');
var i1 = list.indexOf('b');
var i2 = list.indexOf('c');
var i3 = list.indexOf('x');
/*
i0 === 0
@ -1333,11 +1372,11 @@ list.addTailMany([{ x: 1 }, { x: 0 }, { x: 2 }, { x: 0 }, { x: 3 }]);
// {"x":1} <-> {"x":0} <-> {"x":2} <-> {"x":0} <-> {"x":3}
const i0 = indexOf(1, (value, searchedValue) => value.x === searchedValue);
const i1 = indexOf(2, (value, searchedValue) => value.x === searchedValue);
const i2 = indexOf(3, (value, searchedValue) => value.x === searchedValue);
const i3 = indexOf(0, (value, searchedValue) => value.x === searchedValue);
const i4 = indexOf(4, (value, searchedValue) => value.x === searchedValue);
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
@ -1360,13 +1399,13 @@ There are a few ways to iterate over or display a linked list.
#### forEach(callback)
#### forEach(iteratorFn)
```js
forEach(callback: ListIteratorFunction\<T\>): void
forEach(iteratorFn: ListIteratorFn<T>): void
```
Runs a callback function on all nodes in a linked list from head to tail:
Runs a function on all nodes in a linked list from head to tail:
```js
list.addTailMany(['a', 'b', 'c']);
@ -1390,7 +1429,7 @@ list.addTailMany(['a', 'b', 'c']);
// "a" <-> "b" <-> "c"
for(const node of list) {
for(const node of list) { /* ES6 for...of statement */
console.log(node.value);
}
@ -1404,7 +1443,7 @@ for(const node of list) {
#### toArray()
```js
toArray(): T\[\]
toArray(): T[]
```
Converts a linked list to an array of values:
@ -1414,7 +1453,7 @@ list.addTailMany(['a', 'b', 'c']);
// "a" <-> "b" <-> "c"
const arr = list.toArray();
var arr = list.toArray();
/*
arr === ['a', 'b', 'c']
@ -1426,7 +1465,7 @@ arr === ['a', 'b', 'c']
#### toNodeArray()
```js
toNodeArray(): T\[\]
toNodeArray(): ListNode<T>[]
```
Converts a linked list to an array of nodes:
@ -1436,7 +1475,7 @@ list.addTailMany(['a', 'b', 'c']);
// "a" <-> "b" <-> "c"
const arr = list.toNodeArray();
var arr = list.toNodeArray();
/*
arr[0].value === 'a'
@ -1447,10 +1486,10 @@ arr[2].value === 'a'
#### toString()
#### toString([mapperFn])
```js
toString(): string
toString(mapperFn: ListMapperFn<T> = JSON.stringify): string
```
Converts a linked list to a string representation of nodes and their relations:
@ -1460,7 +1499,7 @@ list.addTailMany(['a', 2, 'c', { k: 4, v: 'd' }]);
// "a" <-> 2 <-> "c" <-> {"k":4,"v":"d"}
const str = list.toString();
var str = list.toString();
/*
str === '"a" <-> 2 <-> "c" <-> {"k":4,"v":"d"}'
@ -1476,9 +1515,102 @@ list.addMany([{ x: 1 }, { x: 2 }, { x: 3 }, { x: 4 }, { x: 5 }]).tail();
// {"x":1} <-> {"x":2} <-> {"x":3} <-> {"x":4} <-> {"x":5}
const str = list.toString(value => value.x);
var str = list.toString(value => value.x);
/*
str === '1 <-> 2 <-> 3 <-> 4 <-> 5'
*/
```
```
## API
### Classes
#### LinkedList
```js
export class LinkedList<T = any> {
// properties and methods are explained above
}
```
#### ListNode
```js
export class ListNode<T = any> {
next: ListNode | undefined;
previous: ListNode | undefined;
constructor(public readonly value: T) {}
}
```
`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.
```js
list.addTailMany([ 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
);
```
### Types
#### ListMapperFn
```js
type ListMapperFn<T = any> = (value: T) => any;
```
This function is used in `toString` method to map the node values before generating a string representation of the list.
#### ListComparisonFn
```js
type ListComparisonFn<T = any> = (nodeValue: T, comparedValue: any) => boolean;
```
This function is used while adding, dropping, ang finding nodes based on a comparison value.
#### ListIteratorFn
```js
type ListIteratorFn<T = any, R = boolean> = (
node: ListNode<T>,
index?: number,
list?: LinkedList,
) => R;
```
This function is used while iterating over the list either to do something with each node or to find a node.

@ -371,8 +371,13 @@
"text": "Common",
"items": [
{
"text": "Linked List (Doubly)",
"path": "UI/Common/Utils/Linked-List.md"
"text": "Utilities",
"items": [
{
"text": "Linked List (Doubly)",
"path": "UI/Common/Utils/Linked-List.md"
}
]
}
]
}

@ -3,13 +3,9 @@
import compare from 'just-compare';
export class ListNode<T = any> {
readonly value: T;
next: ListNode | undefined;
previous: ListNode | undefined;
constructor(value: T) {
this.value = value;
}
constructor(public readonly value: T) {}
}
export class LinkedList<T = any> {
@ -354,9 +350,9 @@ export class LinkedList<T = any> {
return -1;
}
forEach<R = boolean>(callback: ListIteratorFn<T, R>) {
forEach<R = boolean>(iteratorFn: ListIteratorFn<T, R>) {
for (let node = this.first, position = 0; node; position++, node = node.next) {
callback(node, position, this);
iteratorFn(node, position, this);
}
}

Loading…
Cancel
Save