Arrays
- API Reference Collections.Arrays module
- Parent Collections module
Enumerating
JS's for of
can be used to enumerate over items in an array:
for (const value of someArray) {
// Do something with value
}
Another classic approach you'll see is a for
loop. This is only useful if you're concerned with the indexes of the items. Most of the time we aren't, which is why the style above is preferred.
// Classic 'for' loop
for (let i=0;i<someArray.length;i++) {
const item = someArray[i]; // access by index
console.log(`${i}. ${someArray[i]}`);
}
Another benefit of the for of
loop is that it can enumerate over different kinds of objects, not just arrays. Most usefully: Generators
Accessing items
Array items can be accessed by their index. The first item in an array has an index of 0, and so on. Arrays have a length
property which returns how many items it contains.
const someArray = [`apples`, `oranges`, `bananas`];
// Get the second item, which has an index of 1
const second = someArray[1];
// Get the last item (length is three, but indexes start at zero, so we have to -1)
const last = someArray[someArray.length-1];
const first = someArray[0];
It also works to use at
, which has the benefit of being able to work backwards:
const someArray = [`apples`, `oranges`, `bananas`];
const second = someArray.at(1);
// Get one item back from start, ie the last item:
const last = someArray.at(-1);
const first = someArray.at(0);
ixfx has some functions for randomly choosing items or indexes from an array: randomElement
returns a random element from an array, randomIndex
returns a random index.
// repl-pad
import {randomElement, randomIndex} from 'https://unpkg.com/ixfx/dist/arrays.js';
// Return a random string: apples, oranges or pears
randomElement([`apples`, `oranges`, `pears`]);
// Return a random index: 0, 1 or 2
randomIndex([`apples`, `oranges`, `pears`]);
weightedInteger
can be used for skewing the distributing of random elements, eg. to favour picking elements at the end of the array over elements at the beginning.
import {weightedInteger} from 'https://unpkg.com/ixfx/dist/random.js';
const a = [`apples`, `oranges`, `melons`, `bananas`];
// Define a function to produce the random numbers we want
const rand = () => weightedInteger({ max: a.length, easing: `quadIn` });
// Use function to access an item in array
a[rand()];
Cycle
cycle
allows traversing an array with function calls. It's useful because the returned function wraps up both the source array and the position. Other parts of your code just need to know to invoke a function and get back a value.
import { cycle } from 'https://unpkg.com/ixfx/dist/arrays.js';
const c = cycle([`apples`,`oranges`,`pears`]);
c.current; // 'apples'
c.next(); // `oranges`
c.next(); // `pears`
c.next(); // `apples'
c.select(1); // 'oranges'
c.select(`pears`); // 'pears'
Finding
JS's some
yields true if at least one item in the array matches the provided function.
For example, if you want to check if there is a green fruit in a list of fruits:
const fruits = [
{colour: `red`, name: `grape`},
{colour: `green`, name: `granny-smith`}
];
// isFound will be true or false
const isFound = fruits.some(v => {
return (v.colour === `green`)
});
JS's includes
returns true if the specified value is found in an array.
const favColours = [ `red`, `green`, `yellow`];
if (favColours.includes(`red`)) {
// Red is in the favourite colours...
}
// Note that favColours.includes(`RED`) would return false
When using includes
to check for objects, be mindful that it compares them by reference not value.
// Returns false, because although object value exists in array,
// this *particular* object does not:
const isFound = fruits.includes({colour: `red`, name: `grape`});
JS's find
function is similar, but it returns the first matching item instead of just true/false.
const firstGreenFruit = fruits.find(v => {
return (v.colour === `green`);
});
// firstGreenFruit will be: {colour: `green`, name: `granny-smith`}
If no matching items were found, undefined
is returned.
const firstPurpleFruit = fruits.find(v v=> v.colour === `purple`); // note simplified arrow function syntax
if (firstPurpleFruit === undefined) {
console.log(`Not found`);
} else {
console.log(`Found: ${firstPurpleFruit.name}`); // Print name of found fruit
}
Ordering
// Ordering and enumerating:
someArray.sort(); // Simple sort
someArray.reverse(); // Reverse order
ixfx's shuffle
randomises the ordering of an array.
// repl-pad#1
import { shuffle } from 'https://unpkg.com/ixfx/dist/arrays.js';
const a = [`apples`, `oranges`, `melons`, `bananas`];
// Yields a randomly ordered version, eg: [`melons`,`apples`,`bananas`,`oranges`];
const b = shuffle(a);
Once shuffled, you can then iterate over the array as normal:
// repl-pad#1
const c = [1,2,3,4,5,6,7,8,9,10];
// Prints items from array in random order
for (const value of shuffle(c)) {
console.log(value);
}
Filtering
without
returns a copy of an array without values equal to v
. In the case of objects, references are compared.
// repl-pad
import { without } from "https://unpkg.com/ixfx/dist/arrays.js"
const data = [1,2,3,1,2,3];
// Yields: [1,3,1,3]
without(data, 2);
JS's in built filter
function all items which pass the provided function:
const data = [1,2,3,1,2,3];
const filtered = data.filter(d => d > 2); // Return true if value is greater than 2
// [3, 3]
ixfx has filterAB
which captures items on either side of the filter function.
import { filterAB } from "https://unpkg.com/ixfx/dist/arrays.js";
const data = [1,2,3,1,2,3]
const [matching,nonMatching] = filterAB(data, d => d > 2);
// matching: [ 3, 3]
// nonMatching: [ 1, 2, 1, 2]
until
returns all items in an array until the provided predicate returns false.
// repl-pad
import { until } from "https://unpkg.com/ixfx/dist/arrays.js"
// Callback gets current value, and needs to return:
// [true/false, accumulated value]
// In this case, we return [true,0] if v === 3
const v = Arrays.until([1,2,3,4,5], v => [v === 3, 0]);
Remove a random element from an array with randomPluck
. It doesn't modify the array, but returns the randomly selected item and a new array without it.
// repl-pad
import {randomPluck} from 'https://unpkg.com/ixfx/dist/arrays.js';
// Remove a random element
const r = randomPluck([`apples`, `oranges`, `pears`]);
r.value; // A random value
r.array; // A copy of the array with the random value removed
Grouping
groupBy
allows you to group an array by some generated key.
// repl-pad
import { groupBy } from "https://unpkg.com/ixfx/dist/arrays.js"
const data = [
{ age: 39, city: `London` }
{ age: 14, city: `Copenhagen` }
{ age: 23, city: `Stockholm` }
{ age: 56, city: `London` }
];
const map = groupBy(data, item => data.city);
This will yield:
{
London: [
{ age: 39, city: `London` },
{ age: 56, city: `London` }
],
Stockhom: [
{ age: 23, city: `Stockholm` }
],
Copenhagen: [
{ age: 14, city: `Copenhagen` }
]
}
Numeric arrays
If you have an array of numbers, ixfx has some functions for common needs.
Overview:
- average, min, max, total or minMaxAvg to calculate all
- averageWeighted
- dotProduct
- weight
Ranges
// repl-pad
import { max,min,average, minMaxAvg } from "https://unpkg.com/ixfx/dist/arrays.js"
const data = [1,2,3];
// Compute max, min, avg:
max(...data); // 3
min(...data); // 1
average(...data); //
// Or compute them all at once:
minMaxAvg(...data);
// Yields: {min: 1, max: 3, avg:, total: 6}
Averages
// repl-pad
import { average } from "https://unpkg.com/ixfx/dist/arrays.js"
// Compute an average of all provided values
average(1, 1.4, 0.9, 0.1); // 0.85
// Compute average of an array
const data = [1,2,3,4,5];
average(...data); // 3
averageWeighted
applies a weighting to each element. In the below example, items in the middle of the array are weighted more highly because of the Gaussian easing function (which resembles a bell curve).
// repl-pad
import { Easings } from "https://unpkg.com/ixfx/dist/modulation.js"
import { averageWeighted } from "https://unpkg.com/ixfx/dist/arrays.js"
// Using an ixfx easing function to weight elements.
// Gaussian function weights middle elements highest, skewing the average
const v = averageWeighted([10,2,3,4,10], Easings.gaussian());
// Yields: 3.6, while regular `average` yields 5.8
Weighting
weight
applies a function (probably an easing function) to some data.
// repl-pad
import { weight } from "https://unpkg.com/ixfx/dist/arrays.js"
import { Easings } from "https://unpkg.com/ixfx/dist/modulation.js"
// Weighs an input array of 1s
weight([1,1,1,1,1,1], Easings.gaussian());
// Yields:
// [0.02, 0.244, 0.85, 0.85, 0.244, 0.02]
More functions
Comparing arrays
compareValues
- for array x and y, identify items common in both, or exclusively in x or ycompareValuesEqual
- returns true if both arrays contain the same set of items, regardless of position.additionalValues
- yield all values not contained in a base arrayintersection
- return values contained in both x and y arraysunique
- combines values of arrays, only keeping unique values
Randomisation
randomIndex
- random indexrandomElement
- random valuerandomPluck
- remove random valueshuffle
- randomise order
Finding/accessing
contains
- returns true if array contains all provided itemscontainsDuplicateValues
- returns true if any duplicate values are found in source array.containsDuplicateInstances
- returns true if any duplicate instances are found in source array.cycle
- cycle through contentsfilterBetween
- return elements of array that match predicate and are within a given start and end indexsample
- sub-sample an arrayvaluesEqual
- returns true if all values in array are identicalfilterAB
- filters an array with a predicate, returning everything that passes in one array and everything that does not in another.
Changing the shape of an array
ensureLength
- Pad out or truncate an array so it matches a target lengthchunks
- break up an array into chunks of a given sizegroupBy
- Groups data by a functioninterleave
- combines the values of several arrays by interleaving valuesremove
- remove an element by indexwithout
- return an array without a given valuezip
- combine elements of arrays based on their index