Arrays

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 y
  • compareValuesEqual - returns true if both arrays contain the same set of items, regardless of position.
  • additionalValues - yield all values not contained in a base array
  • intersection - return values contained in both x and y arrays
  • unique - combines values of arrays, only keeping unique values

Randomisation

Finding/accessing

  • contains - returns true if array contains all provided items
  • containsDuplicateValues - 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 contents
  • filterBetween - return elements of array that match predicate and are within a given start and end index
  • sample - sub-sample an array
  • valuesEqual - returns true if all values in array are identical
  • filterAB - 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 length
  • chunks - break up an array into chunks of a given size
  • groupBy - Groups data by a function
  • interleave - combines the values of several arrays by interleaving values
  • remove - remove an element by index
  • without - return an array without a given value
  • zip - combine elements of arrays based on their index