array

Utility Methods for working with Arrays / Lists

similar to module:group, this is not meant to be exhaustive, only the ones commonly used.

Members

(static) extract

See:

Convenience function for picking specific rows and columns from a 2d array.

Alias of array.pick

Please also see Danfo.js for working with DataFrames.

Example
data = [
 ['john', 23, 'purple'],
 ['jane', 32, 'red'],
 ['ringo', 27, 'green']
];

utils.array.pick(data, {rows: [0, 1]});
//-- [['john', 23, 'purple'], ['jane', 32, 'red']];

utils.array.pick(data, {columns: [0, 2]});
//-- [['john', 'purple'], ['jane', 'red'], ['ringo', 'green']];

utils.array.pick(data, {rows:[0, 1], columns:[0, 2]});
//-- [['john', 'purple'], ['jane', 'red']];

Methods

(static) SORT_ASCENDING()

Simple ascending sort function

Example
[3,5,1,2,4].sort(utils.sort.SIMPLE_ASCENDING))
//
[1,2,3,4,5]

(static) SORT_DESCENDING()

Simple descending sort function

Example
[3,5,1,2,4].sort(utils.sort.SIMPLE_ASCENDING))
//
[5,4,3,2,1]

(static) applyArrayValue(collection, path, value) → {Array}

See:

Applies deeply onto an array safely - in-place using dot-notation paths even if the child paths don't exist.

While tthis can be as simple as safely applying a value even if targetObj may be null

targetObj = [1, 2, null, 4, 5];

utils.object.applyPropertyValue(targetObj, '[2]', 3);
// [1, 2, 3, 4, 5]
// equivalent to targetObj[2] = 3;

This is much more safely working with deeply nested objects

targetObj = [{
 name: 'john smith',
 class: {
   name: 'ECON_101',
   professor: {
     last_name: 'Winklemeyer'
   }
  }
}];

utils.object.applyPropertyValue(targetObj, '[0].class.professor.first_name', 'René');
// [{
//  name: 'john smith',
//  class: {
//    name: 'ECON_101',
//    professor: {
//      last_name: 'Winklemeyer',
//      first_name: 'René' // <- Added
//    }
//   }
// }];

or creating intermediary objects along the path - if they did not exist first.

targetObj = [{
 name: 'john smith'
}];
utils.object.applyPropertyValue(targetObj, '[0].class.professor.first_name', 'René');
[{
 name: 'john smith',
 class: {
   professor: {
     first_name: 'René'
   }
  }
}];
Parameters:
Name Type Description
collection Array

array to apply the value to

path string

dot notation path to set the value, ex: 'geo', or 'states[0].prop'

value any

value to set

Returns:
  • the base array
Type
Array

(static) applyArrayValues(collection, path, value) → {Object}

See:

Converse from the extractPropertyValue, this takes a value / set of values and applies the values for each index in the collection.

for example:

weather = [{ id: 1, city: 'Seattle',  month: 'Aug', precip: 0.87 },
  { id: 3, city: 'New York', month: 'Apr', precip: 3.94 },
  { id: 6, city: 'Chicago',  month: 'Apr', precip: 3.62 }];

cities = utils.object.extractObjectProperty('city');
// ['Seattle', 'New York', 'Chicago'];

//-- async process to geocode
geocodedCities = geocodeCity(cities);
// [{ city: 'Seattle', state: 'WA', country: 'USA' },
// { city: 'New York', state: 'NY', country: 'USA' },
// { city: 'Chicago', state: 'IL', country: 'USA' }]

utils.applyArrayValues(weather, 'geo', geocodedCities);
// [{ id: 1, city: 'Seattle',  month: 'Aug', precip: 0.87, geo: { city: 'Seattle', state: 'WA', country: 'USA' } },
//  { id: 3, city: 'New York', month: 'Apr', precip: 3.94, geo: { city: 'New York', state: 'NY', country: 'USA' } },
//  { id: 6, city: 'Chicago',  month: 'Apr', precip: 3.62, geo: { city: 'Chicago', state: 'IL', country: 'USA' } }];

Note that traditional [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
works best for if you are working with objects completely in memory.

But this helps quite a bit if the action of mapping / transforming values
needs to be separate from the extraction / application of values back.
Parameters:
Name Type Description
collection Array

array to apply the value to on each index

path string

dot notation path to set the value within each index, ex: 'geo', or 'states[0].prop'

value any

the value that should be set at that path.

Returns:
Type
Object

(static) arrange(length, startopt, stepopt) → {Array.<Number>}

See:

Creates an array of values to replace for loops

Example
utils.array.arange(10, 1)
 .map((val) => `item ${val}`);
//
[
  'item 1', 'item 2',
  'item 3', 'item 4',
  'item 5', 'item 6',
  'item 7', 'item 8',
  'item 9', 'item 10'
]
Parameters:
Name Type Attributes Default Description
length Number

the number of items toreturn

start Number <optional>
0

the starting number

step Number <optional>
1

the number to increment for each step

Returns:
  • collection of numbers
Type
Array.<Number>

(static) arrangeMulti(…dimensions)

Creates an array for multiple dimensions of varying sizes.

(In order from higher order dimensions to lower)

utils.array.arangeMulti(0); // []
utils.array.arangeMulti(2); // [0, 1]
utils.array.arangeMulti(4); // [0, 1, 2, 3]
utils.array.arangeMulti(2, 2); // [[0, 1], [0, 1]]
utils.array.arangeMulti(2, 2, 2); // [[[0, 1], [0, 1]], [[0, 1], [0, 1]]]
utils.array.arangeMulti(2, 2, 4); // [[[0, 1, 2, 3], [0, 1, 2, 3]], [[0, 1, 2, 3], [0, 1, 2, 3]]]

Note that this can help with laying items out within a grid

gridPositions = utils.array.arangeMulti(4, 4)
  .reduce((result, row, rowIndex) => [ ...result,
     ...row.reduce((rowReduce, value, columnIndex) => [...rowReduce, [rowIndex, columnIndex]], [])
  ], []);
// [
//   [ 0, 0 ], [ 0, 1 ], [ 0, 2 ], [ 0, 3 ],
//   [ 1, 0 ], [ 1, 1 ], [ 1, 2 ], [ 1, 3 ],
//   [ 2, 0 ], [ 2, 1 ], [ 2, 2 ], [ 2, 3 ],
//   [ 3, 0 ], [ 3, 1 ], [ 3, 2 ], [ 3, 3 ]
// ]

myList.forEach((value, index) => {
  const [x, y] = gridPositions[index];
  console.log(`placing ${value} in row:${x}, column:${y}`);
});
Parameters:
Name Type Attributes Description
dimensions any <repeatable>

sizes of each dimension to create

Returns:

Multi-dimensional array

(static) clone(target)

Deep clones multi-dimensional arrays.

If you want to just deep clone a 1d array, use [...target] instead

NOTE: this only deep clones Arrays, and not the values within the arrays.

const sourceArray = [[0, 1], [2, 3]];
const targetArray = utils.array.clone(sourceArray);

targetArray[0][0] = 99;

console.log(targetArray); // [[99, 1], [2, 3]];
console.log(sourceArray); // [[0, 1], [2, 3]];
Parameters:
Name Type Description
target any | Array

Array to be cloned

Returns:

New deep-cloned array

(static) createSort(fieldName) → {function}

Creates a sort function based on fields of an object.

sampleData = [{score: 200, name: 'jane'}, {score: 200, name: 'john'}]
// sort by score descending, and then by name ascending
sampleData.sort(utils.array.createSort('-score','name'))
Example
sampleData = [{i:4}, {v:2}, {v:1}, {v:3}];
sortedData = sampleData.sort(
   utils.createSort('-v')
);
// [{v:4}, {v:3}, {v:2}, {v:1}]
Parameters:
Name Type Description
fieldName String

name of property to sort by with - for descending

Returns:
Type
function

(static) indexify(source, …sectionIndicatorFunctions) → {Array.<Object>}

Create a unique number index for each element in an array, alternatively using additional functions to indicate hierarchies of data.

For example, markdown can be considered a hierarchy of data:

markdownList = `# Overview
This entire list is a hierarchy of data.

# Section A
This describes section A

## SubSection 1
With a subsection belonging to Section A

## SubSection 2
And another subsection sibling to SubSection 1, but also under Section A.

# Section B
With an entirely unrelated section B, that is sibling to Section A

## SubSection 1
And another subsection 1, but this time related to Section B.`;

And we want to convert this 1d array into a hierarchy.

data = markdownList.split('\n')
   .filter(line => line ? true : false); // check for empty lines

utils.format.consoleLines( data, 4);
// ['# Overview',
// 'This entire list is a hierarchy of data.',
// '# Section A',
// 'This describes section A',;

//-- functions that return True if we are in a new "group"
isHeader1 = (str) => str.startsWith('# ');

isHeader1('# Overview'); // true
isHeader1('This entire list is a hierarchy of data'); // false
isHeader1('# Section A'); // true
isHeader1('This describes section A'); // false

indexedData = utils.array.indexify(data, isHeader1);
[
  { entry: 'Heading', section: [ 0 ], subIndex: 1 },
  { entry: '# Overview', section: [ 1 ], subIndex: 0 },
  {
    entry: 'This entire list is a hierarchy of data.',
    section: [ 1 ],
    subIndex: 1
  },
  { entry: '# Section A', section: [ 2 ], subIndex: 0 },
  { entry: 'This describes section A', section: [ 2 ], subIndex: 1 },
  { entry: '## SubSection 1', section: [ 2 ], subIndex: 2 },
  {
    entry: 'With a subsection belonging to Section A',
    section: [ 2 ],
    subIndex: 3
  },
  { entry: '## SubSection 2', section: [ 2 ], subIndex: 4 },
  {
    entry: 'And another subsection sibling to SubSection 1, but also under Section A.',
    section: [ 2 ],
    subIndex: 5
  },
  { entry: '# Section B', section: [ 3 ], subIndex: 0 },
  {
    entry: 'With an entirely unrelated section B, that is sibling to Section A',
    section: [ 3 ],
    subIndex: 1
  },
  { entry: '## SubSection 1', section: [ 3 ], subIndex: 2 },
  {
    entry: 'And another subsection 1, but this time related to Section B.',
    section: [ 3 ],
    subIndex: 3
  }
];

Note that this only indexes elements by the first header.

To index this with two levels of hierarchy, we can pass another function.

isHeader2 = (str) => str.startsWith('## ');

isHeader2('# Overview'); // false
isHeader2('This entire list is a hierarchy of data'); // false
isHeader2('# Section A'); // true
isHeader2('This describes section A'); // false

indexedData = utils.array.indexify(data, isHeader1, isHeader2);
// [
//   { entry: 'Heading', section: [ 0, 0 ], subIndex: 1 },
//   { entry: '# Overview', section: [ 1, 0 ], subIndex: 0 },
//   {
//     entry: 'This entire list is a hierarchy of data.',
//     section: [ 1, 0 ],
//     subIndex: 1
//   },
//   { entry: '# Section A', section: [ 2, 0 ], subIndex: 0 },
//   { entry: 'This describes section A', section: [ 2, 0 ], subIndex: 1 },
//   { entry: '## SubSection 1', section: [ 2, 1 ], subIndex: 0 },
//   {
//     entry: 'With a subsection belonging to Section A',
//     section: [ 2, 1 ],
//     subIndex: 1
//   },
//   { entry: '## SubSection 2', section: [ 2, 2 ], subIndex: 0 },
//   {
//     entry: 'And another subsection sibling to SubSection 1, but also under Section A.',
//     section: [ 2, 2 ],
//     subIndex: 1
//   },
//   { entry: '# Section B', section: [ 3, 0 ], subIndex: 0 },
//   {
//     entry: 'With an entirely unrelated section B, that is sibling to Section A',
//     section: [ 3, 0 ],
//     subIndex: 1
//   },
//   { entry: '## SubSection 1', section: [ 3, 1 ], subIndex: 0 },
//   {
//     entry: 'And another subsection 1, but this time related to Section B.',
//     section: [ 3, 1 ],
//     subIndex: 1
//   }
// ];
Parameters:
Name Type Attributes Description
source Array

list of values to index

sectionIndicatorFunctions function <repeatable>

each function indicates a new section

Returns:
  • collection of objects, each with a new section (indicating the layers) and subIndex: unique value in the section (always 0 for header)
Type
Array.<Object>

(static) isMultiDimensional(targetArray) → {Boolean}

Determine whether an array is multi-dimensional (an array of arrays)

For example:

utils.array.isMultiDimensional(0); // false
utils.array.isMultiDimensional([0,1,2,3]); // false
utils.array.isMultiDimensional([[0,1], [2,3]]); // true
utils.array.isMultiDimensional([0, [1,2]]); // true
Parameters:
Name Type Description
targetArray Array

array to check if multi-dimensional

Returns:
  • if the targetArray has any values that are multi-dimensional
Type
Boolean

(static) peekFirst(targetArray, defaultVal) → {any}

Peek in an array and return the first value in the array.

Or return the default value (defaultVal) - if the array is empty

Parameters:
Name Type Description
targetArray Array

array to be peeked within

defaultVal any

the value to return if the array is empty

Returns:
Type
any

(static) peekLast(targetArray, defaultVal) → {any}

Peek in an array and return the last value in the array.

Or return the default value (defaultVal) - if the array is empty

Parameters:
Name Type Description
targetArray Array

array to be peeked within

defaultVal any

the value to return if the array is empty

Returns:
Type
any

(static) pick(array2d, options) → {Array}

See:

Convenience function for picking specific rows and columns from a 2d array.

Please also see Danfo.js for working with DataFrames.

Example
data = [
 ['john', 23, 'purple'],
 ['jane', 32, 'red'],
 ['ringo', 27, 'green']
];

utils.array.pick(data, {rows: [0, 1]});
//-- [['john', 23, 'purple'], ['jane', 32, 'red']];

utils.array.pick(data, {columns: [0, 2]});
//-- [['john', 'purple'], ['jane', 'red'], ['ringo', 'green']];

utils.array.pick(data, {rows:[0, 1], columns:[0, 2]});
//-- [['john', 'purple'], ['jane', 'red']];
Parameters:
Name Type Description
array2d Array

2d array to pick from [row][column]

options Object

options on which to pick

Properties
Name Type Attributes Default Description
rows Array.<Number> <optional>
null

indices of the rows to pick

columns Array.<Number> <optional>
null

indices of the columns to pick.

Returns:
    • 2d array of only the rows and columns chosen.
    Type
    Array
    • 2dArray of the columns and rows requested

(static) pickColumns(array2d, …columns)

See:

Picks a column (or multiple columns) from a 2d array

Please also see Danfo.js for working with DataFrames.

Example
data = [
 ['john', 23, 'purple'],
 ['jane', 32, 'red'],
 ['ringo', 27, 'green']
];

utils.array.pickColumns(data, 0);
//-- [['john'], ['jane'], ['ringo']];

utils.array.pickColumns(data, 0, 2);
//-- [['john', 'purple'], ['jane', 'red'], ['ringo', 'green']];
Parameters:
Name Type Attributes Description
array2d Array

2d array to pick from [row][column]

columns any <repeatable>

Indexes of the columns to pick the values from: [0...row.length-1]

Returns:
  • Array with all rows, and only those columns

(static) pickRows(array2d, …rowIndices)

See:

Picks a row (or multiple rows) from a 2d array.

Please also see Danfo.js for working with DataFrames.

Example
data = [
 ['john', 23, 'purple'],
 ['jane', 32, 'red'],
 ['ringo', 27, 'green']
];

utils.array.pickRows(data, 0);
//-- [['john', 23, 'purple']];

utils.array.pickRows(data, 0, 1);
//-- [['john', 23, 'purple'], ['jane', 32, 'red']];
Parameters:
Name Type Attributes Description
array2d Array

2d array to pick from [row][column]

rowIndices Number <repeatable>

Indexes of the row to return, [0...length-1]

Returns:
  • Array with only those rows

(static) reshape(sourceArray, numColumns) → {Array.<Array.<any>>}

Resizes an NxM dimensional array by number of columns

Example
baseArray = utils.array.arrange(12);
[
   0,  1, 2, 3, 4, 5,  6, 7, 8, 9, 10, 11
]

//-- resize the 1d array based on 3 columns
newArray = utils.array.reshape(baseArray, 3)
[ [ 0, 1, 2 ],
  [ 3, 4, 5 ],
  [ 6, 7, 8 ],
  [ 9, 10, 11 ] ];

//-- now resize the 4x3 array to 3x4
utils.array.reshape(newArray, 4);
[ [ 0, 1, 2, 3 ],
  [ 4, 5, 6, 7 ],
  [ 8, 9, 10, 11 ] ]
Parameters:
Name Type Description
sourceArray Array.<any>

an array to resize

numColumns Number

number of columns

Returns:
  • 2 dimensinal array
Type
Array.<Array.<any>>

(static) size(length, defaultValue) → {Array}

See:

Creates an array of a specific size and default value

Especially useful for forLoops, map or reduce

Example
utils.array.size(3, null)
 .map((v, index) => `item ${index}`)
Parameters:
Name Type Description
length Number

the length of the new array

defaultValue any

the new value to put in each cell

Returns:
  • an array of length size with default values
Type
Array

(static) transpose(matrix) → {Array.<any>}

Transposes a two dimensional array, so an NxM becomes MxN

Example
baseArray = [ 0, 1, 2, 3, 4 ];
utils.array.transpose(utils.array.arrange(5))
//
[ [ 0 ],
  [ 1 ],
  [ 2 ],
  [ 3 ],
  [ 4 ] ]
Parameters:
Name Type Description
matrix Array.<any>

MxN array

Returns:
  • NxM array
Type
Array.<any>