Gathering detailed insights and metrics for @shelf/fast-natural-order-by
Gathering detailed insights and metrics for @shelf/fast-natural-order-by
npm install @shelf/fast-natural-order-by
Typescript
Module System
Min. Node Version
77.3
Supply Chain
93.5
Quality
82.9
Maintenance
100
Vulnerability
100
License
Cumulative downloads
Total Downloads
Last day
36.8%
2,400
Compared to previous day
Last week
40.4%
10,887
Compared to previous week
Last month
-5.8%
33,313
Compared to previous month
Last year
55.1%
460,042
Compared to previous year
Lightweight (< 2.3kB gzipped) and performant natural sorting of arrays and collections by differentiating between unicode characters, numbers, dates, etc.
Note: The permormance fixes & typescript were ported into natural-orderby
>3.0.2
, so>2
of this package just re-export the methods of natural-orderby & provide ESM only build A fork of natural-orderby that fixes performance when sorting strings longer than 20 characters (~150,000x faster). Also, re-written from Flow to Typescript
$ yarn add @shelf/fast-natural-order-by
People sort strings containing numbers differently than most sorting algorithms, which sort values by comparing strings in Unicode code point order. This produces an ordering that is inconsistent with human logic.
@shelf/fast-natural-order-by
sorts the primitive values of Boolean
, Null
, Undefined
, Number
or String
type as well as Date
objects. When comparing strings it differentiates between unicode characters, integer, floating as well as hexadecimal numbers, various date formats, etc. You may sort flat or nested arrays or arrays of objects in a natural sorting order using @shelf/fast-natural-order-by
.
In addition to the efficient and fast orderBy()
method @shelf/fast-natural-order-by
also provides the method compare()
, which may be passed to Array.prototype.sort()
.
This is a fork of natural-orderby that fixes performance when sorting strings longer than 20 characters (~150,000x faster).
Here are the benchmark results of sorting array with ONE SINGLE (1) element with a
string 200 chars long that you can run by running yarn benchmark
command:
original:
5 ops/s, ±0.29% | slowest, 100% slower
optimized:
773 712 ops/s, ±0.24% | fastest
See this commit to udnerstand how the performance was fixed.
1import {orderBy} from '@shelf/fast-natural-order-by'; 2 3const users = [ 4 { 5 username: 'Bamm-Bamm', 6 ip: '192.168.5.2', 7 datetime: 'Fri Jun 15 2018 16:48:00 GMT+0200 (CEST)', 8 }, 9 { 10 username: 'Wilma', 11 ip: '192.168.10.1', 12 datetime: '14 Jun 2018 00:00:00 PDT', 13 }, 14 { 15 username: 'Dino', 16 ip: '192.168.0.2', 17 datetime: 'June 15, 2018 14:48:00', 18 }, 19 { 20 username: 'Barney', 21 ip: '192.168.1.1', 22 datetime: 'Thu, 14 Jun 2018 07:00:00 GMT', 23 }, 24 { 25 username: 'Pebbles', 26 ip: '192.168.1.21', 27 datetime: '15 June 2018 14:48 UTC', 28 }, 29 { 30 username: 'Hoppy', 31 ip: '192.168.5.10', 32 datetime: '2018-06-15T14:48:00.000Z', 33 }, 34]; 35 36const sortedUsers = orderBy(users, [v => v.datetime, v => v.ip], ['desc', 'asc']);
This is the return value of orderBy()
:
1[ 2 { 3 username: 'Dino', 4 ip: '192.168.0.2', 5 datetime: 'June 15, 2018 14:48:00', 6 }, 7 { 8 username: 'Pebbles', 9 ip: '192.168.1.21', 10 datetime: '15 June 2018 14:48 UTC', 11 }, 12 { 13 username: 'Bamm-Bamm', 14 ip: '192.168.5.2', 15 datetime: 'Fri Jun 15 2018 16:48:00 GMT+0200 (CEST)', 16 }, 17 { 18 username: 'Hoppy', 19 ip: '192.168.5.10', 20 datetime: '2018-06-15T14:48:00.000Z', 21 }, 22 { 23 username: 'Barney', 24 ip: '192.168.1.1', 25 datetime: 'Thu, 14 Jun 2018 07:00:00 GMT', 26 }, 27 { 28 username: 'Wilma', 29 ip: '192.168.10.1', 30 datetime: '14 Jun 2018 00:00:00 PDT', 31 }, 32];
orderBy()
Creates an array of elements, natural sorted by specified identifiers
and the corresponding sort orders
. This method implements a stable sort algorithm, which means the original sort order of equal elements is preserved.
It also avoids the high overhead caused by Array.prototype.sort()
invoking a compare function multiple times per element within the array.
1function orderBy<T>( 2 collection: ReadonlyArray<T>, 3 identifiers?: ReadonlyArray<Identifier<T>> | Identifier<T>, 4 orders?: ReadonlyArray<Order> | Order 5): Array<T>;
Type | Value |
---|---|
Identifier<T> | string | (value: T) => unknown) |
Order | 'asc' | 'desc' | (valueA: unknown, valueB: unknown) => number |
orderBy()
sorts the elements of an array by specified identifiers and the corresponding sort orders in a natural order and returns a new array containing the sorted elements.
If collection
is an array of primitives, identifiers
may be unspecified. Otherwise, you should specify identifiers
to sort by or collection
will be returned unsorted. An identifier can beexpressed by:
collection
is a nested array,collection
is an array of objects,collection
.If orders
is unspecified, all values are sorted in ascending order. Otherwise, specify an order of 'desc'
for descending or 'asc'
for ascending sort order of corresponding values. You may also specify a compare function for an order, which will be invoked by two arguments: (valueA, valueB)
. It must return a number representing the sort order.
Note:
orderBy()
always returns a new array, even if the original was already sorted.
1import {orderBy} from '@shelf/fast-natural-order-by'; 2 3// Simple numerics 4 5orderBy(['10', 9, 2, '1', '4']); 6// => ['1', 2, '4', 9, '10'] 7 8// Floats 9 10orderBy(['10.0401', 10.022, 10.042, '10.021999']); 11// => ['10.021999', 10.022, '10.0401', 10.042] 12 13// Float & decimal notation 14 15orderBy(['10.04f', '10.039F', '10.038d', '10.037D']); 16// => ['10.037D', '10.038d', '10.039F', '10.04f'] 17 18// Scientific notation 19 20orderBy(['1.528535047e5', '1.528535047e7', '1.528535047e3']); 21// => ['1.528535047e3', '1.528535047e5', '1.528535047e7'] 22 23// IP addresses 24 25orderBy(['192.168.201.100', '192.168.201.12', '192.168.21.1']); 26// => ['192.168.21.1', '192.168.201.12', '192.168.21.100'] 27 28// Filenames 29 30orderBy([ 31 '01asset_0815.png', 32 'asset_47103.jpg', 33 'asset_151.jpg', 34 '001asset_4711.jpg', 35 'asset_342.mp4', 36]); 37// => ['001asset_4711.jpg', '01asset_0815.png', 'asset_151.jpg', 'asset_342.mp4', 'asset_47103.jpg'] 38 39// Filenames - ordered by extension and filename 40 41orderBy( 42 ['01asset_0815.png', 'asset_47103.jpg', 'asset_151.jpg', '001asset_4711.jpg', 'asset_342.mp4'], 43 [v => v.split('.').pop(), v => v] 44); 45// => ['001asset_4711.jpg', 'asset_151.jpg', 'asset_47103.jpg', 'asset_342.mp4', '01asset_0815.png'] 46 47// Dates 48 49orderBy(['10/12/2018', '10/11/2018', '10/11/2017', '10/12/2017']); 50// => ['10/11/2017', '10/12/2017', '10/11/2018', '10/12/2018'] 51 52orderBy([ 53 'Thu, 15 Jun 2017 20:45:30 GMT', 54 'Thu, 3 May 2018 17:45:30 GMT', 55 'Thu, 15 Jun 2017 17:45:30 GMT', 56]); 57// => ['Thu, 15 Jun 2017 17:45:30 GMT', 'Thu, 15 Jun 2018 20:45:30 GMT', 'Thu, 3 May 2018 17:45:30 GMT'] 58 59// Money 60 61orderBy(['$102.00', '$21.10', '$101.02', '$101.01']); 62// => ['$21.10', '$101.01', '$101.02', '$102.00'] 63 64// Case-insensitive sort order 65 66orderBy(['A', 'C', 'E', 'b', 'd', 'f']); 67// => ['A', 'b', 'C', 'd', 'E', 'f'] 68 69// Default ascending sort order 70 71orderBy(['a', 'c', 'f', 'd', 'e', 'b']); 72// => ['a', 'b', 'c', 'd', 'e', 'f'] 73 74// Descending sort order 75 76orderBy(['a', 'c', 'f', 'd', 'e', 'b'], null, ['desc']); 77// => ['f', 'e', 'd', 'c', 'b', 'a'] 78 79// Custom compare function 80 81orderBy([2, 1, 5, 8, 6, 9], null, [(valueA, valueB) => valueA - valueB]); 82// => [1, 2, 5, 6, 8, 9] 83 84// collections 85 86const users = [ 87 { 88 username: 'Bamm-Bamm', 89 ip: '192.168.5.2', 90 datetime: 'Fri Jun 15 2018 16:48:00 GMT+0200 (CEST)', 91 }, 92 { 93 username: 'Wilma', 94 ip: '192.168.10.1', 95 datetime: '14 Jun 2018 00:00:00 PDT', 96 }, 97 { 98 username: 'Dino', 99 ip: '192.168.0.2', 100 datetime: 'June 15, 2018 14:48:00', 101 }, 102 { 103 username: 'Barney', 104 ip: '192.168.1.1', 105 datetime: 'Thu, 14 Jun 2018 07:00:00 GMT', 106 }, 107 { 108 username: 'Pebbles', 109 ip: '192.168.1.21', 110 datetime: '15 June 2018 14:48 UTC', 111 }, 112 { 113 username: 'Hoppy', 114 ip: '192.168.5.10', 115 datetime: '2018-06-15T14:48:00.000Z', 116 }, 117]; 118 119orderBy(users, [v => v.datetime, v => v.ip], ['desc', 'asc']); 120// => [ 121// { 122// username: 'Dino', 123// ip: '192.168.0.2', 124// datetime: 'June 15, 2018 14:48:00', 125// }, 126// { 127// username: 'Pebbles', 128// ip: '192.168.1.21', 129// datetime: '15 June 2018 14:48 UTC', 130// }, 131// { 132// username: 'Bamm-Bamm', 133// ip: '192.168.5.2', 134// datetime: 'Fri Jun 15 2018 16:48:00 GMT+0200 (CEST)', 135// }, 136// { 137// username: 'Hoppy', 138// ip: '192.168.5.10', 139// datetime: '2018-06-15T14:48:00.000Z', 140// }, 141// { 142// username: 'Barney', 143// ip: '192.168.1.1', 144// datetime: 'Thu, 14 Jun 2018 07:00:00 GMT', 145// }, 146// { 147// username: 'Wilma', 148// ip: '192.168.10.1', 149// datetime: '14 Jun 2018 00:00:00 PDT', 150// }, 151// ]
compare()
Creates a compare function that defines the natural sort order and which may be passed to Array.prototype.sort()
.
1compare(options?: CompareOptions): CompareFn
Type | Value |
---|---|
CompareOptions | { order?: 'asc' | 'desc' } |
CompareFn | (valueA: unknown, valueB: unknown) => number |
compare()
returns a compare function that defines the natural sort order and which may be passed to Array.prototype.sort()
.
If options
or its property order
is unspecified, values are sorted in ascending sort order. Otherwise, specify an order of 'desc'
for descending or 'asc'
for ascending sort order of values.
1import { compare } from '@shelf/fast-natural-order-by'; 2 3// Simple numerics 4 5['10', 9, 2, '1', '4'].sort(compare()); 6// => ['1', 2, '4', 9, '10'] 7 8 9// Floats 10 11['10.0401', 10.022, 10.042, '10.021999'].sort(compare()); 12// => ['10.021999', 10.022, '10.0401', 10.042] 13 14 15// Float & decimal notation 16 17['10.04f', '10.039F', '10.038d', '10.037D'].sort(compare()); 18// => ['10.037D', '10.038d', '10.039F', '10.04f'] 19 20 21// Scientific notation 22 23['1.528535047e5', '1.528535047e7', '1.528535047e3'].sort(compare()); 24// => ['1.528535047e3', '1.528535047e5', '1.528535047e7'] 25 26 27// IP addresses 28 29['192.168.201.100', '192.168.201.12', '192.168.21.1'].sort(compare()); 30// => ['192.168.21.1', '192.168.201.12', '192.168.21.100'] 31 32 33// Filenames 34 35['01asset_0815.jpg', 'asset_47103.jpg', 'asset_151.jpg', '001asset_4711.jpg', 'asset_342.mp4'].sort(compare()); 36// => ['001asset_4711.jpg', '01asset_0815.jpg', 'asset_151.jpg', 'asset_342.mp4', 'asset_47103.jpg'] 37 38 39// Dates 40 41['10/12/2018', '10/11/2018', '10/11/2017', '10/12/2017'].sort(compare()); 42// => ['10/11/2017', '10/12/2017', '10/11/2018', '10/12/2018'] 43 44['Thu, 15 Jun 2017 20:45:30 GMT', 'Thu, 3 May 2018 17:45:30 GMT', 'Thu, 15 Jun 2017 17:45:30 GMT'].sort(compare()); 45// => ['Thu, 15 Jun 2017 17:45:30 GMT', 'Thu, 15 Jun 2018 20:45:30 GMT', 'Thu, 3 May 2018 17:45:30 GMT'] 46 47 48// Money 49 50['$102.00', '$21.10', '$101.02', '$101.01'].sort(compare()); 51// => ['$21.10', '$101.01', '$101.02', '$102.00'] 52 53 54// Case-insensitive sort order 55 56['A', 'C', 'E', 'b', 'd', 'f'].sort(compare()); 57// => ['A', 'b', 'C', 'd', 'E', 'f'] 58 59 60// Default ascending sort order 61 62['a', 'c', 'f', 'd', 'e', 'b'].sort(compare()); 63// => ['a', 'b', 'c', 'd', 'e', 'f'] 64 65 66// Descending sort order 67 68['a', 'c', 'f', 'd', 'e', 'b'].sort(compare({ order: 'desc' })); 69// => ['f', 'e', 'd', 'c', 'b', 'a'] 70 71 72// collections 73 74const users = [ 75 { 76 username: 'Bamm-Bamm', 77 lastLogin: { 78 ip: '192.168.5.2', 79 datetime: 'Fri Jun 15 2018 16:48:00 GMT+0200 (CEST)' 80 }, 81 }, 82 { 83 username: 'Wilma', 84 lastLogin: { 85 ip: '192.168.10.1', 86 datetime: '14 Jun 2018 00:00:00 PDT' 87 }, 88 }, 89 { 90 username: 'Dino', 91 lastLogin: { 92 ip: '192.168.0.2', 93 datetime: 'June 15, 2018 14:48:00' 94 }, 95 }, 96 { 97 username: 'Barney', 98 lastLogin: { 99 ip: '192.168.1.1', 100 datetime: 'Thu, 14 Jun 2018 07:00:00 GMT' 101 }, 102 }, 103 { 104 username: 'Pebbles', 105 lastLogin: { 106 ip: '192.168.1.21', 107 datetime: '15 June 2018 14:48 UTC' 108 }, 109 }, 110 { 111 username: 'Hoppy', 112 lastLogin: { 113 ip: '192.168.5.10', 114 datetime: '2018-06-15T14:48:00.000Z' 115 }, 116 }, 117]; 118 119users.sort((a, b) => compare()(a.lastLogin.ip, b.lastLogin.ip)); 120// => [ 121// { 122// username: 'Dino', 123// lastLogin: { 124// ip: '192.168.0.2', 125// datetime: 'June 15, 2018 14:48:00' 126// }, 127// }, 128// { 129// username: 'Barney', 130// lastLogin: { 131// ip: '192.168.1.1', 132// datetime: 'Thu, 14 Jun 2018 07:00:00 GMT' 133// }, 134// }, 135// { 136// username: 'Pebbles', 137// lastLogin: { 138// ip: '192.168.1.21', 139// datetime: '15 June 2018 14:48 UTC' 140// }, 141// }, 142// { 143// username: 'Bamm-Bamm', 144// lastLogin: { 145// ip: '192.168.5.2', 146// datetime: 'Fri Jun 15 2018 16:48:00 GMT+0200 (CEST)' 147// }, 148// }, 149// { 150// username: 'Hoppy', 151// lastLogin: { 152// ip: '192.168.5.10', 153// datetime: '2018-06-15T14:48:00.000Z' 154// }, 155// }, 156// { 157// username: 'Wilma', 158// lastLogin: { 159// ip: '192.168.10.1', 160// datetime: '14 Jun 2018 00:00:00 PDT' 161// }, 162// }, 163// ]
1$ git checkout master 2$ yarn version 3$ yarn publish 4$ git push origin master --tags
MIT © Shelf
No vulnerabilities found.
No security vulnerabilities found.