Skip to content

Commit ba5f748

Browse files
Adds implementation of arrayToTree, tests, documentation and configuration
1 parent 0778033 commit ba5f748

16 files changed

+1769
-1
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/coverage
2+
/node_modules
3+
/.env

README.md

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,94 @@
1-
1+
# Performant array to tree
2+
3+
[![npm version](https://img.shields.io/npm/v/npm.svg)](https://www.npmjs.com/package/performant-array-to-tree)
4+
[![minified size](https://img.shields.io/badge/minified_size-0.448_kb-brightgreen.svg)](#typescript)
5+
[![CircleCI](https://circleci.com/gh/philipstanislaus/performant-array-to-tree.svg?style=shield&circle-token=01828caf71908b915230609847a12272cc80c54d)](https://circleci.com/gh/philipstanislaus/performant-array-to-tree)
6+
[![Coverage Status](https://coveralls.io/repos/github/philipstanislaus/performant-array-to-tree/badge.svg?branch=master)](https://coveralls.io/github/philipstanislaus/performant-array-to-tree?branch=master)
7+
[![Dependency Status](https://david-dm.org/philipstanislaus/performant-array-to-tree.svg)](https://david-dm.org/philipstanislaus/performant-array-to-tree)
8+
[![devDependency Status](https://david-dm.org/philipstanislaus/performant-array-to-tree/dev-status.svg)](https://david-dm.org/philipstanislaus/performant-array-to-tree#info=devDependencies)
9+
[![typings included](https://img.shields.io/badge/typings-included-brightgreen.svg)](#typescript)
10+
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
11+
[![npm](https://img.shields.io/npm/l/express.svg)](https://www.npmjs.com/package/performant-array-to-tree)
12+
13+
Converts an array of items with ids and parent ids to a nested tree in a performant `O(n)` way. Runs in browsers and node.
14+
15+
## Why another package
16+
17+
Other packages have stricter assumptions or are not as performant, as they often use multiple loops or recursion. For example:
18+
19+
[o-unflatten](https://www.npmjs.com/package/o-unflatten) requires the input to be ordered such that parent nodes always come before their children.
20+
[array-to-tree](https://www.npmjs.com/package/array-to-tree) uses two loops (runs with `O(2n)`), one for grouping all items by their parents, and one for creating the tree.
21+
[un-flatten-tree](https://www.npmjs.com/package/un-flatten-tree) uses 2 nested loops (runs even worse with `O(n^2)`).
22+
23+
This implementation does not require any order of items in the input array and focuses on runtime performance. By only using a single loop (runs with `O(n)`). It was inspired by [this discussion](http://stackoverflow.com/questions/444296/how-to-efficiently-build-a-tree-from-a-flat-structure) on StackOverflow.
24+
25+
## Installation
26+
27+
`yarn add performant-array-to-tree`
28+
29+
or if using npm
30+
31+
`npm install --save performant-array-to-tree`
32+
33+
## Usage
34+
35+
```js
36+
const tree = arrayToTree([
37+
{ id: '4', parentId: null, custom: 'abc' },
38+
{ id: '31', parentId: '4', custom: '12' },
39+
{ id: '1941', parentId: '418', custom: 'de' },
40+
{ id: '1', parentId: '418', custom: 'ZZZz' },
41+
{ id: '418', parentId: null, custom: 'ü'},
42+
])
43+
44+
// output
45+
tree === [
46+
{ data: { id: '4', parentId: null, custom: 'abc' }, children: [
47+
{ data: { id: '31', parentId: '4', custom: '12' }, children: [] },
48+
] },
49+
{ data: { id: '418', parentId: null, custom: 'ü'}, children: [
50+
{ data: { id: '1941', parentId: '418', custom: 'de' }, children: [] },
51+
{ data: { id: '1', parentId: '418', custom: 'ZZZz' }, children: [] },
52+
] },
53+
]
54+
```
55+
56+
## Configuration
57+
58+
You can provide a second argument to arrayToTree with configuration options. Right now, you can set the following:
59+
60+
- `id`: key of the id field of the item
61+
- `parentId`: key of the parent's id field of the item
62+
63+
Example:
64+
65+
```js
66+
const tree = arrayToTree([
67+
{ num: '4', ref: null, custom: 'abc' },
68+
{ num: '31', ref: '4', custom: '12' },
69+
{ num: '1941', ref: '418', custom: 'de' },
70+
{ num: '1', ref: '418', custom: 'ZZZz' },
71+
{ num: '418', ref: null, custom: 'ü'},
72+
], { id: 'num', parentId: 'ref' })
73+
74+
// output
75+
tree === [
76+
{ data: { num: '4', ref: null, custom: 'abc' }, children: [
77+
{ data: { num: '31', ref: '4', custom: '12' }, children: [] },
78+
] },
79+
{ data: { num: '418', ref: null, custom: 'ü'}, children: [
80+
{ data: { num: '1941', ref: '418', custom: 'de' }, children: [] },
81+
{ data: { num: '1', ref: '418', custom: 'ZZZz' }, children: [] },
82+
] },
83+
]
84+
```
85+
86+
## TypeScript
87+
88+
This project includes types, just import the module as usual:
89+
90+
```ts
91+
import * as arrayToTree from 'performant-array-to-tree'
92+
93+
const tree = arrayToTree(array)
94+
```

build/arrayToTree.d.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export interface Item {
2+
id: string;
3+
parentId: string | null;
4+
[key: string]: any;
5+
}
6+
export interface TreeItem {
7+
data?: Item;
8+
children: TreeItem[];
9+
}
10+
export interface Config {
11+
id: string;
12+
parentId: string;
13+
}
14+
/**
15+
* Unflattens an array to a tree with runtime O(n)
16+
*/
17+
export declare function arrayToTree(items: Item[], config?: Config): TreeItem[];

build/arrayToTree.js

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/arrayToTree.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/arrayToTree.min.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/arrayToTree.spec.d.ts

Whitespace-only changes.

build/arrayToTree.spec.js

Lines changed: 44 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/arrayToTree.spec.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

circle.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
machine:
2+
node:
3+
version: 6
4+
5+
dependencies:
6+
pre:
7+
- npm install --global yarn
8+
override:
9+
- yarn
10+
11+
test:
12+
override:
13+
- yarn run lint
14+
- yarn run test-and-send-cov-to-coveralls
15+
- yarn run build

0 commit comments

Comments
 (0)