{"id":13646868,"url":"https://github.com/klaudiosinani/singlie","last_synced_at":"2025-09-12T21:14:08.047Z","repository":{"id":57361770,"uuid":"137698326","full_name":"klaudiosinani/singlie","owner":"klaudiosinani","description":"Singly circular \u0026 linear linked lists for ES6","archived":false,"fork":false,"pushed_at":"2019-10-29T09:39:51.000Z","size":597,"stargazers_count":186,"open_issues_count":1,"forks_count":3,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-24T06:07:47.098Z","etag":null,"topics":["circular","es6","linear","linked","list","singly","typescript"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/klaudiosinani.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":"contributing.md","funding":".github/funding.yml","license":"license.md","code_of_conduct":"code-of-conduct.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"klaussinani"}},"created_at":"2018-06-18T01:05:43.000Z","updated_at":"2024-08-31T21:06:26.000Z","dependencies_parsed_at":"2022-09-26T16:41:03.978Z","dependency_job_id":null,"html_url":"https://github.com/klaudiosinani/singlie","commit_stats":null,"previous_names":["klaussinani/singlie"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klaudiosinani%2Fsinglie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klaudiosinani%2Fsinglie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klaudiosinani%2Fsinglie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/klaudiosinani%2Fsinglie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/klaudiosinani","download_url":"https://codeload.github.com/klaudiosinani/singlie/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250573352,"owners_count":21452352,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["circular","es6","linear","linked","list","singly","typescript"],"created_at":"2024-08-02T01:03:11.989Z","updated_at":"2025-04-24T06:07:53.894Z","avatar_url":"https://github.com/klaudiosinani.png","language":"JavaScript","funding_links":["https://github.com/sponsors/klaussinani"],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n  Singlie\n\u003c/h1\u003e\n\n\u003ch4 align=\"center\"\u003e\n  Singly circular \u0026 linear linked lists for ES6\n\u003c/h4\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://travis-ci.com/klaussinani/singlie\"\u003e\n    \u003cimg alt=\"Build Status\" src=\"https://travis-ci.com/klaussinani/singlie.svg?branch=master\"\u003e\n  \u003c/a\u003e\n  \u003ca href='https://coveralls.io/github/klaussinani/singlie?branch=master'\u003e\n    \u003cimg alt=\"Coverage Status\" src=\"https://coveralls.io/repos/github/klaussinani/singlie/badge.svg?branch=master\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## Description\n\nES6 implementation of the circular and linear singly linked list data structures with TypeScript support.\n\nCome over to [Gitter](https://gitter.im/klaussinani/singlie) to share your thoughts on the project.\n\nVisit the [contributing guidelines](https://github.com/klaussinani/singlie/blob/master/contributing.md#translating-documentation) to learn more on how to translate this document into more languages.\n\n## Contents\n\n- [Description](#description)\n- [Install](#install)\n- [Usage](#usage)\n- [In Depth](#in-depth)\n- [API](#api)\n- [Development](#development)\n- [Related](#related)\n- [Team](#team)\n- [License](#license)\n\n## Install\n\n### Yarn\n\n```bash\nyarn add singlie\n```\n\n### NPM\n\n```bash\nnpm install singlie\n```\n\n## Usage\n\nSinglie exposes a chainable API, that can be utilized through a simple and minimal syntax, allowing you to combine methods effectively.\n\nUsage examples can be also found at the [`test`](https://github.com/klaussinani/singlie/tree/master/test) directory.\n\n```js\nconst {Circular, Linear} = require('singlie');\n\nconst linear = new Linear();\nlinear.prepend('A').append('B');\nlinear.head;\n// =\u003e Node { value: 'A', next: Node { value: 'B', next: null } }\nlinear.head.next;\n// =\u003e Node { value: 'B', next: null }\nlinear.head.next.next;\n// =\u003e null\nlinear.map(x =\u003e `[${x}]`).reverse().join(' -\u003e ');\n// =\u003e [B] -\u003e [A]\n\nconst circular = new Circular();\ncircular.append('B').prepend('A');\ncircular.head;\n// =\u003e Node { value: 'A', next: Node { value: 'B', next: [Circular] } }\ncircular.head.next;\n// =\u003e Node { value: 'B', next: Node { value: 'A', next: [Circular] } }\ncircular.head.next.next;\n// =\u003e Node { value: 'A', next: Node { value: 'B', next: [Circular] } }\ncircular.map(x =\u003e `[${x}]`).reverse().toArray();\n// =\u003e [ '[B]', '[A]' ]\n```\n\n## In Depth\n\n### Linear Singly Linked List\n\nLinear singly linked lists can contain multiple nodes, where each node has only a `value` and a `next` attribute. The `value` attribute holds the value stored inside of the node, and the `next` attribute points to the next node in line. The only exception, is that the last node of the list has `null` stored to its `next` attribute, which indicates the lack of further nodes down the line, thus the end of the list. The following example demonstrates the operations that can be performed on any linear singly linked list.\n\n```js\nconst {Linear} = require('singlie');\n\nconst linear = new Linear();\n\n// Append a node holding the value `E`\nlinear.append('E');\nlinear.head; // =\u003e Node { value: 'E', next: null }\nlinear.last; // =\u003e Node { value: 'E', next: null }\nlinear.get(0); // =\u003e E\n\n// Return the node corresponding to the index\nlinear.node(0); // =\u003e Node { value: 'E', next: null }\nlinear.node(0).value; // =\u003e E\nlinear.node(0).next; // =\u003e null\n\n// Append multiple nodes at once\nlinear.append('F', 'G');\nlinear.length; // =\u003e 3\nlinear.node(0).next.value; // =\u003e F\nlinear.node(0).next.next.value; // =\u003e G\nlinear.toArray(); // =\u003e [ 'E', 'F', 'G' ]\n\n// Prepend multiple nodes at once\nlinear.prepend('B', 'A');\nlinear.join(' '); // =\u003e A B E F G\n\n// Insert multiple nodes to the given index\nlinear.insert({value: ['D', 'C', 'X'], index: 2});\nlinear.join(' '); // =\u003e A B X C D E F G\n\n// Remove the node corresponding to the index\nlinear.remove(2);\nlinear.join(' '); // =\u003e A B C D E F G\n\n// Update the value of the node corresponding to the index\nlinear.node(linear.length - 1).value = '!';\nlinear.join(' '); // =\u003e A B C D E F !\nlinear.set({value: 'G', index: linear.length - 1});\nlinear.join(' '); // =\u003e A B C D E F G\n\n// Iterate over the list\nconst array = [];\nlinear.forEach(x =\u003e array.push(x));\nlog(array);\n// =\u003e [ 'A', 'B', 'C', 'D', 'E', 'F', 'G' ]\n\n// Chain multiple methods\nlinear.reverse().map(x =\u003e `[${x}]`).join('-\u003e');\n// =\u003e [G]-\u003e[F]-\u003e[E]-\u003e[D]-\u003e[C]-\u003e[B]-\u003e[A]\n\n// Clear the list\nlinear.clear(); // =\u003e Linear { head: null, length: 0 }\n```\n\n### Circular Singly Linked List\n\nCircular singly linked lists can also contain multiple nodes, where again each node has the same `value` and `next` attributes. The only difference compared to linear lists, is that the last node always points back to the first node / head of the list, thus the list is said to be circular or circularly linked. The following example demonstrates the operations that can be performed on any circular singly linked list.\n\n```js\nconst {Circular} = require('singlie');\n\nconst circular = new Circular();\nconst {log} = console;\n\n// Append a node holding the value `E`\ncircular.append('E');\ncircular.head; // =\u003e Node { value: 'E', next: [Circular] }\ncircular.last; // =\u003e Node { value: 'E', next: [Circular] }\ncircular.get(0); // =\u003e E\n\n// Return the node corresponding to the index\ncircular.node(0); // =\u003e Node { value: 'E', next: [Circular] }\ncircular.node(0).value; // =\u003e E\ncircular.node(0).next.value; // =\u003e E\ncircular.node(0).next.next.value; // =\u003e E\n\n// Append multiple nodes at once\ncircular.append('F', 'G');\ncircular.length; // =\u003e 3\ncircular.node(0).next.value; // =\u003e F\ncircular.node(0).next.next.value; // =\u003e G\ncircular.node(0).next.next.next.value; // =\u003e E\ncircular.toArray(); // =\u003e [ 'E', 'F', 'G' ]\n\n// Prepend multiple nodes at once\ncircular.prepend('B', 'A');\ncircular.join(' '); // =\u003e A B E F G\n\n// Insert multiple nodes to the given index\ncircular.insert({value: ['D', 'C', 'X'], index: 2});\ncircular.join(' '); // =\u003e A B X C D E F G\n\n// Remove the node corresponding to the index\ncircular.remove(2);\ncircular.join(' '); // =\u003e A B C D E F G\n\n// Update the value of the node corresponding to the index\ncircular.node(circular.length - 1).value = '!';\ncircular.join(' '); // =\u003e A B C D E F !\ncircular.set({value: 'G', index: circular.length - 1});\ncircular.join(' '); // =\u003e A B C D E F G\n\n// Iterate over the list\nconst array = [];\ncircular.forEach(x =\u003e array.push(x));\nlog(array);\n// =\u003e [ 'A', 'B', 'C', 'D', 'E', 'F', 'G' ]\n\n// Chain multiple methods\ncircular.reverse().map(x =\u003e `[${x}]`).join('-\u003e');\n// =\u003e [G]-\u003e[F]-\u003e[E]-\u003e[D]-\u003e[C]-\u003e[B]-\u003e[A]\n\n// Clear the list\ncircular.clear(); // =\u003e Circular { head: null, length: 0 }\n```\n\n## API\n\nThe following documentation holds for both circular \u0026 linear lists. The described `list` instance is used to depict the same methods that are applicable to both a linear and a circular linked list, without overlooking their above described differences and unique qualities.\n\n#### list.`append(value[, value])`\n\n- Return Type: `Linked List`\n\nAppends one of more nodes to the list.\n\n##### **`value`**\n\n- Type: `any`\n\nCan be one or more comma delimited values. Each value corresponds to a single node.\n\n```js\nlist.append('A', 'B', 'C', 'D');\n// =\u003e { value: 'A', next: { value: 'B', next: [List] } }\n```\n\n#### list.`prepend(value[, value])`\n\n- Return Type: `Linked List`\n\nPrepends one of more nodes to the list.\n\n##### **`value`**\n\n- Type: `any`\n\nCan be one or more comma delimited values. Each value corresponds to a single node.\n\n```js\nlist.append('C' , 'D');\n// =\u003e { value: 'C', next: [List] }\nlist.prepend('B', 'A');\n// =\u003e { value: 'A', next: { value: 'B', next: { value: 'C', next: [List] } } }\n```\n\n#### list.`head`\n\n- Return Type: `Node | null`\n\nReturns the first node / head on the list.\n\n```js\nlist.append('A', 'B');\nlist.head;\n// =\u003e Node { value: 'A', next: [Node] }\n```\n\n#### list.`last`\n\n- Return Type: `Node | null`\n\nReturns the last node on the list.\n\n```js\nlist.append('A', 'B');\nlist.last;\n// =\u003e Node { value: 'B', next: [Node] }\n```\n\n#### list.`length`\n\n- Return Type: `Integer`\n\nReturns the length of the list.\n\n```js\nlist.append('A', 'B');\nlist.length;\n// =\u003e 2\n```\n\n#### list.`isEmpty()`\n\n- Return Type: `Boolean`\n\nChecks whether or not the list is empty.\n\n```js\nlist.append('A', 'B');\nlist.isEmpty();\n// =\u003e false\n```\n\n#### list.`insert({value[, value], index})`\n\n- Return Type: `Linked List`\n\nInserts one or more nodes to the given index.\n\n##### **`value`**\n\n- Type: `any`\n\nCan be one or more comma delimited values. Each value corresponds to a single node.\n\n##### **`index`**\n\n- Type: `Integer`\n\nCan be an integer corresponding to a list index.\n\n```js\nlist.append('A', 'B', 'E');\nlist.insert({value: ['C', 'D'], index: 1});\n// =\u003e { value: 'A', next: { value: 'D', next: { value: 'C', next: { value: 'B', next: [List] } } } }\n```\n\n#### list.`node(index)`\n\n- Return Type: `Node`\n\nReturn the node corresponding to the given index.\n\n##### **`index`**\n\n- Type: `Integer`\n\nCan be an integer corresponding to a list index.\n\n```js\nlist.append('A', 'B', 'C', 'D');\nconst node = list.node(0);\n// =\u003e { value: 'A', next: { value: 'B', next: [List] } }\nnode.value;\n// =\u003e A\nnode.next;\n// =\u003e { value: 'B', next: [List] }\n```\n\n#### list.`get(index)`\n\n- Return Type: `any`\n\nReturn the value of node corresponding to the given index.\n\n##### **`index`**\n\n- Type: `Integer`\n\nCan be an integer corresponding to a list index.\n\n```js\nlist.append('A', 'B');\n\nlist.get(0);\n// =\u003e A\nlist.get(0);\n// =\u003e B\n```\n\n#### list.`remove(index)`\n\n- Return Type: `Linked List`\n\nRemoves from the list the node located to the given index.\n\n##### **`index`**\n\n- Type: `Integer`\n- Default: `list.length - 1`\n\nCan be an integer corresponding to a list index.\n\nIf not provided, the last node of the list will be removed.\n\n```js\nlist.append('A', 'B', 'C', 'D');\n// =\u003e { value: 'A', next: [List] }\nlist.remove(0);\n// =\u003e { value: 'B', next: [List] }\nlist.remove(0);\n// =\u003e { value: 'C', next: [List] }\n```\n\n#### list.`toArray()`\n\n- Return Type: `Array`\n\nConverts the list into an array.\n\n```js\nlist.append('A', 'B', 'C');\n// =\u003e { value: 'A', next: { value: 'B', next: [List] } }\nconst array = list.toArray();\n// =\u003e [ 'A', 'B', 'C' ]\n```\n\n#### list.`clear()`\n\n- Return Type: `Linked List`\n\nRemoves all nodes from the list.\n\n```js\nlist.append('A', 'B', 'C');\n// =\u003e { value: 'A', next: { value: 'B', next: [List] } }\nlist.clear();\n// =\u003e null\n```\n\n#### list.`join([separator])`\n\n- Return Type: `String`\n\nJoins the values of all nodes on the list into a string and returns the string.\n\n##### **`separator`**\n\n- Type: `String`\n- Default: `Comma ','`\n\nSpecifies a string to separate each pair of adjacent node values of the array. \n\nIf omitted, the node values are separated with a `comma ','`.\n\n```js\nlist.append('A', 'B', 'C');\n// =\u003e { value: 'A', next: { value: 'B', next: [List] } }\nlist.join();\n// =\u003e 'A,B,C'\nlist.join('');\n// =\u003e 'ABC'\nlist.join(' ');\n// =\u003e 'A B C'\n```\n\n#### list.`forEach(function)`\n\n- Return Type: `Linked List`\n\nExecutes a provided function once for each node value.\n\n##### **`function`**\n\n- Type: `Function`\n\nFunction to execute for each node value.\n\n```js\nconst array = [];\nlist.append('A', 'B', 'C');\n// =\u003e { value: 'A', next: { value: 'B', next: [List] } }\nlist.forEach(x =\u003e array.push(x));\nconsole.log(array);\n// =\u003e [ 'A', 'B', 'C' ];\n```\n\n#### list.`map(function)`\n\n- Return Type: `Linked List`\n\nExecutes a provided function once for each node value.\n\n##### **`function`**\n\n- Type: `Function`\n\nFunction that produces a new node value for the new list.\n\n```js\nlist.append('A', 'B', 'C');\n// =\u003e { value: 'A', next: { value: 'B', next: [List] } }\nconst mapped = list.map(x =\u003e `[${x}]`);\narray.join(' ');\n// =\u003e '[A] [B] [C]'\n```\n\n#### list.`filter(function)`\n\n- Return Type: `Linked List`\n\nCreates a new liked list with all elements that pass the test implemented by the provided function.\n\n##### **`function`**\n\n- Type: `Function`\n\nFunction is a predicate, to test each element of the list. Return true to keep the element, false otherwise.\n\n```js\nlist.append(1, 2, 3, 4, 5, 6);\n// =\u003e { value: 1, next: { value: 2, next: [List] } }\nconst filtered = list.filter(x =\u003e x % 2 \u003e 0);\nfiltered.toArray();\n// =\u003e [ 1, 3, 5 ]\n```\n\n#### list.`reduce(function, initialValue)`\n\n- Return Type: `Any`\n\nExecutes a reducer function on each member of the list resulting in a single output value.\n\n##### **`function`**\n\n- Type: `Function`\n\nThe reducer function takes two arguments: accumulator \u0026 current value. The reducer function's returned value is assigned to the accumulator, whose value is remembered across each iteration throughout the list and ultimately becomes the final, single resulting value.\n\n```js\nlist.append(20, 50, 35, 41, 5, 67);\n// =\u003e { value: 20, next: { value: 50, next: [List] } }\nlist.reduce((acc, x) =\u003e acc \u003e x ? acc : x, -Infinity);\n// =\u003e 67\n```\n\n#### list.`includes(value)`\n\n- Return Type: `Boolean`\n\nThe method determines whether a list, circular or linear, includes a certain value among its nodes, returning `true` or `false` as appropriate.\n\n##### **`value`**\n\n- Type: `Any`\n\nThe value to search for.\n\n```js\nlist.append(20, 50, 35, 41, 5, 67);\n// =\u003e { value: 20, next: { value: 50, next: [List] } }\nlist.includes();\n// =\u003e false\nlist.includes(0);\n// =\u003e false\nlist.includes(50);\n// =\u003e true\n```\n\n#### list.`indexOf(value)`\n\n- Return Type: `Number`\n\nThe method returns the first index at which a given element can be found in the circular/linear linked list, or -1 if it is not present.\n\n##### **`value`**\n\n- Type: `Any`\n\nElement to locate in the array.\n\n```js\nlist.append(20, 50, 35, 41, 5, 67);\n// =\u003e { value: 20, next: { value: 50, next: [List] } }\nlist.indexOf();\n// =\u003e -1\nlist.indexOf(0);\n// =\u003e -1\nlist.indexOf(41);\n// =\u003e 3\n```\n\n#### list.`toString()`\n\n- Return Type: `String`\n\nReturns a string representing the specified list and its elements.\n\n```js\nlist.append(20, 50, 35, 41, 5, 67);\n// =\u003e '20,50,35,41,5,67'\n```\n\n#### list.`isCircular()`\n\n- Return Type: `Boolean`\n\nReturns `true` if the linked list is circular or `false` if it is linear.\n\n```js\nconst {Circular} = require('singlie');\n\nconst list = new Circular();\n\nlist.isCircular();\n// =\u003e true\n```\n\n#### list.`isLinear()`\n\n- Return Type: `Boolean`\n\nReturns `true` if the linked list is linear or `false` if it is circular.\n\n```js\nconst {Circular} = require('singlie');\n\nconst list = new Circular();\n\nlist.isLinear();\n// =\u003e false\n```\n\n#### linear.`toCircular()`\n\n- Return Type: `Circular Linked List`\n\nReturns a new circular linked list containing all elements of the original linear linked list.\n\n```js\nconst {Linear} = require('singlie');\n\nconst list = new Linear();\n\nlist.toCircular().isLinear();\n// =\u003e false\n```\n\n#### circular.`toLinear()`\n\n- Return Type: `Linear Linked List`\n\nReturns a new linear linked list containing all elements of the original circular linked list.\n\n```js\nconst {Circular} = require('singlie');\n\nconst list = new Circular();\n\nlist.toLinear().isLinear();\n// =\u003e true\n```\n\nAlso available, along with the `Circular` and `Linear` exposed classes, is the `Node` class, mainly useful for testing purposes, since it can be utilized to compare nodes residing in linear \u0026 circular linked lists. The class has a unary constructor method, with a `'value'` parameter, corresponding to the data stored in the created instance. \n\nAdditionally, each `Node` instance has the following two public properties: \n\n#### node.`value`\n\n- Return Type: `any`\n\nThe value that the node contains.\n\n```js\nconst {Node} = require('singlie');\n\nconst node = new Node('A');\n// =\u003e { value: 'A', next: null }\n\nnode.value;\n//=\u003e 'A'\n\nnode.value = 'B' // Update the `value` attribute to 'B'\n// =\u003e { value: 'B', next: null }\n```\n\n#### node.`next`\n\n- Return Type: `Node | null`\n\nThe next node in line, that the targeted node instance points to.\n\n```js\nconst {Node} = require('singlie');\n\nconst node1 = new Node('A');\n// =\u003e { value: 'A', next: null }\n\nnode1.next\n//=\u003e null\n\nconst node2 = new Node('B');\n\nnode1.next = node2; // `node1` now points to `node2`\n//=\u003e { value: 'A', next: { value: 'B', next: null } }\n```\n\n## Development\n\nFor more info on how to contribute to the project, please read the [contributing guidelines](https://github.com/klaussinani/singlie/blob/master/contributing.md).\n\n- Fork the repository and clone it to your machine\n- Navigate to your local fork: `cd singlie`\n- Install the project dependencies: `npm install` or `yarn install`\n- Lint the code and run the tests: `npm test` or `yarn test`\n\n## Related\n\n- [avlbinstree](https://github.com/klaussinani/avlbinstree) - AVL self-balancing binary search trees for ES6\n- [binoheap](https://github.com/klaussinani/binoheap) - Binomial heaps for ES6\n- [binstree](https://github.com/klaussinani/binstree) - Binary search trees for ES6\n- [doublie](https://github.com/klaussinani/doublie) - Doubly circular \u0026 linear linked lists for ES6\n- [dsforest](https://github.com/klaussinani/dsforest) - Disjoint-set forests for ES6\n- [kiu](https://github.com/klaussinani/kiu) - FIFO Queues for ES6\n- [mheap](https://github.com/klaussinani/mheap) - Binary min \u0026 max heaps for ES6\n- [prioqueue](https://github.com/klaussinani/prioqueue) - Priority queues for ES6\n- [shtack](https://github.com/klaussinani/shtack) - LIFO Stacks for ES6\n\n## Team\n\n- Klaus Sinani [(@klaussinani)](https://github.com/klaussinani)\n\n## License\n\n[MIT](https://github.com/klaussinani/singlie/blob/master/license.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklaudiosinani%2Fsinglie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fklaudiosinani%2Fsinglie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fklaudiosinani%2Fsinglie/lists"}