antimutable-array
This library provides a set of functions that can be used as an alternative to
built-in array methods and provide following value proposition:
- Passed array is never mutated.
- If operation is noop passed array is returned instead of copy.
- Library will do as little allocations as possible. (For example in majority of case where result is empty array same frozen empty array is returned).
- Library is fully flow typed.
- Functions have a more composable interface.
Usage
Functions are grouped by built-in array methods that they provide alternative for. Examples presume following in the scope:
import AntimutableArray from 'antimutable-array'
push <value> (item:value, items:Array<value>) => Array<value>
Similar to Array.prototype.push
but instead of mutating array in place and returning a new length, returns new array with given element added to the end of the passed array.
AntimutableArray.push(5, [1, 2, 3])
reverse <value> (items:Array<value>) => Array<value>
Same as Array.prototype.reverse
but instead of mutating array in place returns new array with it's elements in reversed order.
AntimutableArray.reverse([1, 2, 3])
Built-in Array.prototype.shift
does multiple things:
- Gets you an array with first element removed (by mutating given array).
- Gets you the first element of the array, if available (as return value).
Usually you would need either first element or rest elements of the array and
this library provides:
drop <value> (n:number, items:Array<value>) => Array<value>
Returns you array containing all but the first n
elements of the given array.
AntimutableArray.drop(2, [1, 2, 3, 4])
AntimutableArray.drop(4, [1, 2, 3, 4])
It can be used in place of Array.prototype.shift
when you need to get an array without it's first element as simply as:
AntimutableArray.drop(1, [2, 3, 4])
first <value> (items:Array<value>) => ?value
Return first element of the array unless array is empty, in later case void is returned. This can be used in place of Array.prototype.shift
when you need return value of it. Or in place of array[0]
.
AntimutableArray.first([1, 2, 3, 4])
AntimutableArray.first([4])
AntimutableArray.first([]) == null
const [first, ...rest] = array
In some cases you need both return value of the Array.prototype.shift
and a mutated array (that no longer contains first element). In those cases use of destructuring syntax is the best immutable alternative:
const [first, ...rest] = [1, 2, 3, 4]
first
rest
Instead of function with optional argument library provides two functions
sort <value> (items:Array<value>) => Array<value>
Returns an array with elements of the given array sorted in order of string unicode code points (same order as array.sort()
).
AntimutableArray.sort([1, 5, 0, 9, 7])
sortBy = <v> (f:(a:v, b:v) => number, items:Array<v>) => Array<v>
Returns an array with elements of the given array sorted via give compare function (compare function has same API as in Array.prototype.sort
).
const descending =
(a, b) =>
a > b
? -1
: a < b
? 1
: 0
AntimutableArray.sortBy(descending, [1, 5, 0, 9, 7])
Built-in Array.prototype.splice
can do multiple things:
- Give you an array with some items removed.
- Give you an array with some items inserted.
- Give you an array with some items removed & some inserted.
Usually you do need to either insert or remove elements from the array, more rarely you need to do both at the same time. This library covers individual use case with a separate function with designated interface.
remove <v> (index:number, n:number, items:Array<v>) => Array<v>
Returns array with n
number of elements removed from the given array starting from given index
.
AntimutableArray.remove(1, 1, [1, 2, 3, 4, 5])
AntimutableArray.remove(1, 3, [1, 2, 3, 4, 5])
When n
is negative that number of elements preceding the index
are excluded instead.
AntimutableArray.remove(3, -2, [1, 2, 3, 4, 5])
AntimutableArray.remove(5, -3, [1, 2, 3, 4, 5])
If index
is out of bounds (less than 0 or greater than number of elemnet in array) then only elements with in the array bounds are removed if such elements exist:
AntimutableArray.remove(-3, 5, [1, 2, 3, 4, 5])
AntimutableArray.remove(7, -5, [1, 2, 3, 4, 5])
AntimutableArray.remove(7, -2, [1, 2, 3, 4, 5])
AntimutableArray.remove(-4, 2, [1, 2, 3, 4, 5])
AntimutableArray.remove(-4, -2, [1, 2, 3, 4, 5])
insert <v> (index:number, include:Array<v>, items:Array<v>) => Array<v>
Returns array with elements of given include
array included in the given items
array at the given index
offset.
AntimutableArray.insert(1, [0, 7], [1, 2, 3, 4])
AntimutableArray.insert(3, [0, 7], [1, 2, 3, 4])
If passed index
is negative it is treated as index from the end of the array instead:
AntimutableArray.insert(-1, [0, 7], [1, 2, 3, 4])
AntimutableArray.insert(-7, [0, 7], [1, 2, 3, 4])
substitute <v> (index:number, n:number, add:Array<v>, src:Array<v>) => Array<v>
If you need to do both exclude and include items in one step then there is this function that behaves pretty much same as Array.prototype.splice
but without mutating passed array (name is intentionally different due to slight API differences).
AntimutableArray.substitute(2, 3, [0, 7], [1, 2, 3, 4, 5, 6])
AntimutableArray.substitute(-3, 2, [8, 8], [1, 2, 3, 4, 5])
unshift <value> (item:value, items:Array<value>):Array<value>
Returns array with given item
as first element followed by elements of given items
array.
AntimutableArray.unshift(0, [1, 2, 3])
Built-in Array.prototype.concat
is variadic and also somewhat error prone due to treating non array arguments as array of only that argument. Instead library provides two different functions.
append <value> (left:Array<value>, right:Array<value>) => Array<value>
Returns new array with elements of given left
array followed by elements of the given right
array:
AntimutableArray.append([0, 1], [7, 8, 9])
concat <value> (arrays:Array<Array<value>>) => Array<value>
Returns array that represents concatenation of the elements in the supplied arrays
.
AntimutableArray.concat([[1, 2], [3], [], [4, 5]])
Array.prototype.slice
drop <value> (n:number, items:Array<value>) => Array<value>
Returns an array containing all but the first n
elements from the supplied items
array.
AntimutableArray.drop(2, [1, 2, 3, 4, 5])
AntimutableArray.drop(0, [1, 2, 3, 4, 5])
AntimutableArray.drop(9, [1, 2, 3, 4, 5])
take <value> (n:number, items:Array<value>) => Array<value>
Returns an array of the first n
elements from the supplied items
array, or all items if there are fewer than n
.
AntimutableArray.take(2, [1, 2, 3, 4, 5])
AntimutableArray.take(0, [1, 2, 3, 4, 5])
AntimutableArray.take(9, [1, 2, 3, 4, 5])
slice <v> (start:number, end:number, items:Array<v>) => Array<v>
Returns an array containing elements starting from start
index to end
index from the supplied items
array:
AntimutableArray.slice(0, 2, [1, 2, 3, 4, 5])
AntimutableArray.slice(2, 4, [1, 2, 3, 4, 5])
Negative start
and end
indexes are resolved from the end of the supplied items
array.
AntimutableArray.slice(-4, 4, [1, 2, 3, 4, 5])
AntimutableArray.slice(-5, -2, [1, 2, 3, 4, 5])
array[2] = 3
set <v> (index:number, item:v, items:Array<v>) => Array<v>
Returns a new array with elements of the supplied items
array, but with an element at given index
replaced with given item
element.
AntimutableArray.set(2, 0, [1, 2, 3, 4, 5])
If index
is negative it is resolved from the rear of the array (Which provides arguably nicer interface to array[array.length - 1] = 2
).
AntimutableArray.set(-1, 0, [1, 2, 3, 4, 5])
If index
is out of bounds then it is a noop. If you want to just add element to the end consider push
instead. As of array holes that would kind of degrade type of the array from Array<value>
to Array<?value>
so it's considered anti-feature:
AntimutableArray.set(6, 0, [1, 2, 3, 4, 5])
AntimutableArray.set(16, 0, [1, 2, 3, 4, 5])
array[n]
first <value> (items:Array<value>) => ?value
Returns the first element of the supplied array, or void if array contains no elements. Kind of alternative to array[0]
but can be passed, composed, etc..
AntimutableArray.first([1, 2, 3])
AntimutableArray.first([]) == null
last <value> (items:Array<value>) => ?value
Returns the last element of the supplied array, or void if array contains no elements. Kind of alternative to array[array.length - 1]
but can be passed, composed, etc..
AntimutableArray.last([1, 2, 3])
AntimutableArray.last([]) == null
get <value> (n:number, items:Array<value>) => ?value
Returns n
-th element of the supplied array or void if array contains no such element.
AntimutableArray.get(4, [1, 2, 3, 4, 5])
AntimutableArray.get(0, [1, 2, 3, 4, 5])
AntimutableArray.get(2, [1, 2, 3, 4, 5])
If n
is negative it is resolved from the end of the supplied array:
AntimutableArray.get(-1, [1, 2, 3, 4, 5])
AntimutableArray.get(-5, [1, 2, 3, 4, 5])
AntimutableArray.get(-2, [1, 2, 3, 4, 5])
[]
It is not really necessary but handy at a times.
empty
Frozen empty array that is often returned by this library functions when result of the operation is an empty array.
AntimutableArray.empty
Install
npm install antimutable-array
[Array.prototype.push]: