Utility Methods for working with Arrays / Lists
similar to module:group, this is not meant to be exhaustive, only the ones commonly used.
- Generate Array
- array.size(size, default) - generate array of a specific size and CONSISTENT default value
- array.arrange(size, start, step) - generate array of a size, and INCREASING default value
- array.arrangeMulti(n, m, ...) - generate a multi-dimensional array
- array.clone(array) - deep clones arrays
- array.zip(arrayleft, arrayRight) - zips two arrays to join values at the same index together.
- Sorting
- array.createSort(sortIndex, sortIndex, ...) - generates a sorting function
- array.SORT_ASCENDING - common ascending sorting function for array.sort()
- array.SORT_DESCENDING - common descending sorting function for array.sort()
- array.indexify - identify sections within a 1d array to create a hierarchy.
- Rearrange Array
- array.reshape - reshapes an array to a size of rows and columns
- array.transpose - transposes (flips - the array along the diagonal)
- array.resize - repeats or truncates to change the size of an array.
- Picking Values
- array.peekFirst - peeks at the first value in the list
- array.peekLast - peeks at the last value in the list
- array.pickRows - picks a row from a 2d array
- array.pickColumns - picks a column from a 2d array
- array.pick - picks either/or rows and columns
- Extracting Array Values
- array.extract - synonym to array.pick to pick either a row or column from an array
- array.multiLineSubstr - Extract Substr from a multi-line string or array of strings
- array.multiLineSubstring - Extract Substring from a multi-line string or array of strings
- array.multiStepReduce - Performs reduce, and returns the value of reduce at each step
- array.extractFromHardSpacedTable - Extract values where each line has no delimiter, but instead a column index (ex: column 13)
- Applying a value
- array.applyArrayValue - applies a value deeply into an array safely
- array.applyArrayValues - applies a value / multiple values deeply into an array safely
- Understanding Values
- array.isMultiDimensional - determines if an array is multi-dimensional
- Custom Iterators
- PeekableArrayIterator - Iterator that lets you peek ahead while not moving the iterator.
- Iterating over values
- delayedFn - Similar to Function.bind() - you specify a function and arguments only to be called when you ask
- chainFunctions - Chain a set of functions to be called one after another.
- asyncWaitAndChain - Chains a set of functions to run one after another, but with a delay between.
Classes
Members
(static) extract
- See:
-
- module:array.pickRows - picking rows
- module:array.pickColumns - picking columns
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.array.SIMPLE_ASCENDING)
// [1,2,3,4,5]
(static) SORT_DESCENDING()
Simple descending sort function
Example
[3,5,1,2,4].sort(utils.array.SORT_DESCENDING)
// [5,4,3,2,1]
(static) applyArrayValue(collection, path, value) → {Array}
- See:
-
- array.pick - to pick a row or column into an array
- array.applyArrayValues - applies an array safely and deeply onto another array of values
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:
-
- array.applyArrayValue - to apply a single value to a single object
- array.pick - to pick a row or column into an array
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'];
//-- get a separate dataset that needs to be joined, like geocodeCity(cities);
geocodedCities = [{ city: 'Seattle', state: 'WA', country: 'USA' },
{ city: 'New York', state: 'NY', country: 'USA' },
{ city: 'Chicago', state: 'IL', country: 'USA' }];
utils.array.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 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:
-
- module:array.size for consistent values in the array
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 ]
// ]
gridPositions.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) asyncWaitAndChain(seconds, fn, rows) → {Promise.<any>}
- See:
-
- chainFunctions - to execute methods right after each other.
- rxjs if you would like to execute more than one at a time.
Similar to chainFunctions - in that only one delayed function will occur at a time, but adds a delay between calls.
This also supports functions returning promises.
const sumValues = (...rest) => rest.reduce((result, val) => result + val, 0);
const arguments = [
[1],
[1, 1],
[1, 1, 2],
[1, 1, 2, 3]
];
utils.array.asyncWaitAndChain(3, sumValues, arguments)
.then((results) => console.log(`fibonnacci numbers: ${results}`));
// fibonacci numbers: [1, 2, 4, 7], but took 9 seconds to accomplish
Parameters:
| Name | Type | Description |
|---|---|---|
seconds |
Number | number of seconds to delay between each execution |
fn |
function | function to be called for each row of rows |
rows |
Array.<Array.<any>> | Array where each row are arguments to be applied to fn |
Returns:
- promise that will resolve when the last delayed function finishes
- Type
- Promise.<any>
(static) chainFunctions(fn, rows) → {Promise.<any>}
- See:
-
- rxjs if you would like to have more than one active at a time.
- asyncWaitAndChain - if you would like a delay between executions
Chain a set of functions to be called one after another (supports functions returning promises)
This is especially helpful if calls need to be rate limited to only having 1 occur at a time.
The resulting promise will return a list, with each entry corresponding with the row of arguments sent.
const sumValues = (...rest) => rest.reduce((result, val) => result + val, 0);
const arguments = [
[1],
[1, 1],
[1, 1, 2],
[1, 1, 2, 3]
];
utils.array.chainFunctions(sumValues, arguments)
.then((results) => console.log(`fibonnacci numbers: ${results}`));
// fibonacci numbers: [1, 2, 4, 7]
Parameters:
| Name | Type | Description |
|---|---|---|
fn |
function | the function to be called |
rows |
Array.<Array.<any>> | Array where each row are arguments to be applied to fn |
Returns:
- promise that will resolve when the last delayed function finishes
- Type
- Promise.<any>
(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.
[{score: 200, name: 'jane'}, {score: 300, name: 'john'}, {score: 300, name: 'jonny'}];
// sort by score descending, and then by name ascending
sampleData.sort(utils.array.createSort('-score','name'));
// [{ score: 300, name: 'john' }, { score: 300, name: 'jonny' },{ score: 200, name: 'jane' }]
Example
sampleData = [{i:4}, {v:2}, {v:1}, {v:3}];
sortedData = sampleData.sort(
utils.array.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) delayedFn(fn, …rest) → {function}
Defines a function and arguments that will only be called, only when the delayedFunction is called.
(Similar to Function.bind - but supports Function.call(1,2,3) or Function.apply([1,2,3]) syntax)
Example, these are equivalent, but the delayedFn does not mess with this
sayFn = (...rest) => console.log(...rest); arguments = [0, 1, 2, 3, 4, 5];
Spy(sayFn);
delayedFnA = sayFn.bind(globalThis, arguments); ... sayFn.calledCount; // 0 delayedFnA(); // consoles: [0, 1, 2, 3, 4, 5]; sayFn.calledCount; // 1
delayedFnB = utils.array.delayedFn(sayFn, 0, 1, 2, 3, 4, 5); ... delayedFnB(); // consoles: [0, 1, 2, 3, 4, 5];
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
fn |
function | Function to be executed at a later time |
|
rest |
any |
<repeatable> |
arguments to be passed to fn |
Returns:
- function that can be called to execute fn with the arguments
- Type
- function
(static) extractFromHardSpacedTable(str, columnWidths) → {Array.<Array.<String>>}
Useful for extracting out hard spaced string arrays separated by newlines
hardSpacedString = `
id first_name last_name city email gender ip_address airport_code car_model_year
-- ---------- ---------- ----------- ---------------------------- ------ --------------- ------------ --------------
1 Thekla Brokenshaw Chicago tbrokenshaw0@kickstarter.com Female 81.118.170.238 CXI 2003
2 Lexi Dugall New York ldugall1@fc2.com Female 255.140.25.31 LBH 2005
3 Shawna Burghill London sburghill2@scribd.com Female 149.240.166.189 GBA 2004
4 Ginger Tween Lainqu gtween3@wordpress.com Female 132.67.225.203 EMS 1993
5 Elbertina Setford Los Angeles esetford4@ted.com Female 247.123.242.49 MEK 1989 `;
columns = [
'id ',
'first_name ',
'last_name ',
'city ',
'email ',
'gender ',
'ip_address ',
'airport_code ',
'car_model_year '
];
columnWidths = columns.map((str) => str.length);
// [ 3, 11, 11, 12, 29, 7, 16, 13, 15 ];
results = utils.array.extractFromHardSpacedTable(hardSpacedString, columnWidths);
// [['id ', '-- ', '1 ', '2 ', '3 ', '4 ', '5 '],
// ['first_name ', '---------- ', 'Thekla ', 'Lexi ', 'Shawna ', 'Gin...', ...],
// ['last_name ', '---------- ', 'Brokenshaw ', 'Dugall ', 'Burghill ', 'Twe...', ...],
// ['city ', '----------- ', 'Chicago ', 'New York ', 'London ', ...],
// ['email ', '---------------------------- ', 'tbrokenshaw0...', ...],
// ['gender ', '------ ', 'Female ', 'Female ', 'Female ', 'Female ', 'Female '],
// ['ip_address ', '--------------- ', '81.118.170.238 ', '255.140.25.31 ', ...],
// ['airport_code ', '------------ ', 'CXI ', 'LBH ', 'GBA ...', ...],
// ['car_model_year', '--------------', '2003 ', '2005 ', '2004 ...', ...]]
We can then transpose the array to give us the format we might expect (non DataFrame centric)
resultsData = utils.array.transpose(results);
utils.table(resultsData).render();
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|
| id | first_name | last_name | city | gender | ip_address | airport_code | car_model_year | |
| -- | ---------- | ---------- | ----------- | ---------------------------- | ------ | --------------- | ------------ | -------------- |
| 1 | Thekla | Brokenshaw | Chicago | tbrokenshaw0@kickstarter.com | Female | 81.118.170.238 | CXI | 2003 |
| 2 | Lexi | Dugall | New York | ldugall1@fc2.com | Female | 255.140.25.31 | LBH | 2005 |
| 3 | Shawna | Burghill | London | sburghill2@scribd.com | Female | 149.240.166.189 | GBA | 2004 |
| 4 | Ginger | Tween | Lainqu | gtween3@wordpress.com | Female | 132.67.225.203 | EMS | 1993 |
| 5 | Elbertina | Setford | Los Angeles | esetford4@ted.com | Female | 247.123.242.49 | MEK | 1989 |
Parameters:
| Name | Type | Description |
|---|---|---|
str |
String | Markdown / Hard Spaced Strings |
columnWidths |
Array.<Number> | Array of of the column widths to extract |
Returns:
- Array of Arrays, where each row is an extracted column
- Type
- Array.<Array.<String>>
(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) multiLineSubstr(str, start, lenopt) → {Array.<String>}
- See:
-
- multiLineSubstring - to use start and end character positions
- multiStepReduce - for example on how to extract data from hard spaced arrays array.size(size, default) - generate array of a specific size and CONSISTENT default value
Parse a fixed length table of strings (often in markdown format)
This is different from multiLineSubString in this uses a start position and string length (not start and end position per line)
For example, say you got a string formatted like this:
hardSpacedString = '' +
`id first_name last_name city email gender ip_address airport_code car_model_year
-- ---------- ---------- ----------- ---------------------------- ------ --------------- ------------ --------------
1 Thekla Brokenshaw Chicago tbrokenshaw0@kickstarter.com Female 81.118.170.238 CXI 2003
2 Lexi Dugall New York ldugall1@fc2.com Female 255.140.25.31 LBH 2005
3 Shawna Burghill London sburghill2@scribd.com Female 149.240.166.189 GBA 2004
4 Ginger Tween Lainqu gtween3@wordpress.com Female 132.67.225.203 EMS 1993
5 Elbertina Setford Los Angeles esetford4@ted.com Female 247.123.242.49 MEK 1989 `;
This can be a bit hard to parse, because the space delimiter is a valid character in the city column, ex: New York.
Instead, we can use the starting index and number of characters, to extract the data out
const carModelYears = ArrayUtils.multiLineSubstr(hardSpacedString, 102);
// ['car_model_year', '--------------', '2003 ', '2005 ', '2004 ', '1993 ', '1989'];
const ipAddresses = ArrayUtils.multiLineSubstr(hardSpacedString, 73, 14);
// ['ip_address ', '--------------', '81.118.170.238', '255.140.25.31 ', '149.240.166.18', '132.67.225.203', '247.123.242.49'];
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
str |
String | Array.<String> | multi-line string or array of strings |
||
start |
Number | the starting index to substr |
||
len |
Number |
<optional> |
0
|
optional length of string to substr |
Returns:
- substr values from each line
- Type
- Array.<String>
(static) multiLineSubstring(str, startPosition, endPositionopt) → {Array.<String>}
- See:
-
- multiLineSubstr - to use character start and length
- multiStepReduce - for example on how to extract data from hard spaced arrays
Parse a fixed length table of strings (often in markdown format)
This is different from multiLineSubStr in this uses a start and end position (not start and length)
For example, say you got a string formatted like this:
hardSpacedString = '' +
`id first_name last_name city email gender ip_address airport_code car_model_year
-- ---------- ---------- ----------- ---------------------------- ------ --------------- ------------ --------------
1 Thekla Brokenshaw Chicago tbrokenshaw0@kickstarter.com Female 81.118.170.238 CXI 2003
2 Lexi Dugall New York ldugall1@fc2.com Female 255.140.25.31 LBH 2005
3 Shawna Burghill London sburghill2@scribd.com Female 149.240.166.189 GBA 2004
4 Ginger Tween Lainqu gtween3@wordpress.com Female 132.67.225.203 EMS 1993
5 Elbertina Setford Los Angeles esetford4@ted.com Female 247.123.242.49 MEK 1989 `;
This can be a bit hard to parse, because the space delimiter is a valid character in the city column, ex: New York.
Instead, we can use the starting index and number of characters, to extract the data out.
Note, this function uses the starting and ending character positions, to extract, where multiLineSubstr - uses the start and character length instead.
const carModelYears = ArrayUtils.multiLineSubstring(hardSpacedString, 102);
// ['car_model_year', '--------------', '2003 ', '2005 ', '2004 ', '1993 ', '1989'];
const ipAddresses = ArrayUtils.multiLineSubstring(hardSpacedString, 73, 87);
// ['ip_address ', '--------------', '81.118.170.238', '255.140.25.31 ', '149.240.166.18', '132.67.225.203', '247.123.242.49'];
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
str |
String | Array.<String> | multi-line string or array of strings |
|
startPosition |
Number | the starting index to extract out - using the standard |
|
endPosition |
Number |
<optional> |
the ending endex to extract out |
Returns:
- substr values from each line
- Type
- Array.<String>
(static) multiStepReduce()
Returns the reduce at each step along the way.
For example, if you have a set of column widths and would like to know how wide the table is after each column.
For example:
hardSpacedString = '' +
`id first_name last_name city email gender ip_address airport_code car_model_year
-- ---------- ---------- ----------- ---------------------------- ------ --------------- ------------ --------------
1 Thekla Brokenshaw Chicago tbrokenshaw0@kickstarter.com Female 81.118.170.238 CXI 2003
2 Lexi Dugall New York ldugall1@fc2.com Female 255.140.25.31 LBH 2005
3 Shawna Burghill London sburghill2@scribd.com Female 149.240.166.189 GBA 2004
4 Ginger Tween Lainqu gtween3@wordpress.com Female 132.67.225.203 EMS 1993
5 Elbertina Setford Los Angeles esetford4@ted.com Female 247.123.242.49 MEK 1989 `;
columns = [
'id ',
'first_name ',
'last_name ',
'city ',
'email ',
'gender ',
'ip_address ',
'airport_code ',
'car_model_year '
];
columnWidths = columns.map((str) => str.length);
// [ 3, 11, 11, 12, 29, 7, 16, 13, 15 ];
//-- get the starting position for each column,
//-- ex: column 3 is sum of columnWidths[0..3] or 0 + 3 + 11 + 11 or 25
columnStops = utils.array.multiStepReduce( columnWidths, (a,b) => a + b, 0);
// [0, 3, 14, 25, 37, 66, 73, 89, 102, 117];
We can then pair with the column widths - to get exactly the starting position and width of each column.
substrPairs = columnWidths.map((value, index) => [columnStops[index], value]);
// [[0, 3], [3, 11], [14, 11], [25, 12], [37, 29], [66, 7], [73, 16], [89, 13], [102, 15]];
Now that we know how the starting positions for each of the columns, we can try picking one column out:
//-- we can get a single column like this:
cityStartingCharacter = substrPairs[3][0]; // 25
cityColumnLength = substrPairs[3][1]; // 12
cityData = utils.array.multiLineSubstr(hardSpacedString, cityStartingCharacter, cityColumnLength);
// ['city ', '----------- ', 'Chicago ', 'New York ', 'London ', 'Lainqu ', 'Los Angeles ']
Or we can get all columns with something like this:
results = substrPairs.map(
([startingPos, length]) => utils.array.multiLineSubstr(hardSpacedString, startingPos, length)
);
// [['id ', '-- ', '1 ', '2 ', '3 ', '4 ', '5 '],
// ['first_name ', '---------- ', 'Thekla ', 'Lexi ', 'Shawna ', 'Gin...', ...],
// ['last_name ', '---------- ', 'Brokenshaw ', 'Dugall ', 'Burghill ', 'Twe...', ...],
// ['city ', '----------- ', 'Chicago ', 'New York ', 'London ', ...],
// ['email ', '---------------------------- ', 'tbrokenshaw0...', ...],
// ['gender ', '------ ', 'Female ', 'Female ', 'Female ', 'Female ', 'Female '],
// ['ip_address ', '--------------- ', '81.118.170.238 ', '255.140.25.31 ', ...],
// ['airport_code ', '------------ ', 'CXI ', 'LBH ', 'GBA ...', ...],
// ['car_model_year', '--------------', '2003 ', '2005 ', '2004 ...', ...]]
We can then transpose the array to give us the format we might expect (non DataFrame centric)
resultsData = utils.array.transpose(results);
utils.table(resultsData).render();
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|
| id | first_name | last_name | city | gender | ip_address | airport_code | car_model_year | |
| -- | ---------- | ---------- | ----------- | ---------------------------- | ------ | --------------- | ------------ | -------------- |
| 1 | Thekla | Brokenshaw | Chicago | tbrokenshaw0@kickstarter.com | Female | 81.118.170.238 | CXI | 2003 |
| 2 | Lexi | Dugall | New York | ldugall1@fc2.com | Female | 255.140.25.31 | LBH | 2005 |
| 3 | Shawna | Burghill | London | sburghill2@scribd.com | Female | 149.240.166.189 | GBA | 2004 |
| 4 | Ginger | Tween | Lainqu | gtween3@wordpress.com | Female | 132.67.225.203 | EMS | 1993 |
| 5 | Elbertina | Setford | Los Angeles | esetford4@ted.com | Female | 247.123.242.49 | MEK | 1989 |
This can also be helpful with coming up with complex array.arrange(size, start, step) collections.
(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:
-
- array.pickRows - picking rows
- array.pickColumns - picking columns
- array.applyArrayValues - applies a value / multiple values deeply into an array safely
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
|
Returns:
-
- 2d array of only the rows and columns chosen.
- Type
- Array
-
- 2dArray of the columns and rows requested
(static) pickColumns(array2d, …columns)
- See:
-
- array.pick - pick either rows or columns
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:
-
- array.pick - pick either rows or columns
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>>}
Re-shapes 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
// ]
//-- reshape 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 reshape 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 reshape |
numColumns |
Number | number of columns |
Returns:
- 2 dimensinal array
- Type
- Array.<Array.<any>>
(static) resize(sourceList, length)
Resizes an array - if shorter (truncates), if longer cycles values.
categoryValues = ['rock', 'paper', 'scissors'];
//-- resizes an array to be shorter - truncating
utils.array.resize(categoryValues, 2); // ['rock', 'paper']
//-- resizes an array to be longer - filling with undefined
utils.array.resize(categoryValues, 7); // ['rock', 'paper', 'scissors', undefined, undefined, undefined, undefined];
Parameters:
| Name | Type | Description |
|---|---|---|
sourceList |
Array | array of values |
length |
Number | new length of the list |
(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>
(static) zip(arrayLeft, arrayRight, …rest) → {Array.<Array>}
Combines arrays together by joining the values at the same index.
Similar to Panda's zip
This can be very helpful for joining multiple value lists.
first = ['john', 'paul', 'george', 'ringo'];
last = ['lennon', 'mccartney', 'harrison', 'starr'];
phrase = ['imagine', 'yesterday', 'taxman', 'walrus'];
names = utils.array.zip(first, last);
// [['john', 'lennon'], ['paul', 'mccartney'],
// ['george', 'harrison'], ['ringo', 'starr']];
You can also zip together existing arrays
utils.array.zip(names, phrase);
// [['john', 'lennon', 'imagine'],
// ['paul', 'mccartney', 'yesterday'],
// ['george', 'harrison', 'taxman'],
// ['ringo', 'starr', 'walrus']]
or you can zip them together all at once
utils.array.zip(first, last, phrase);
// [['john', 'lennon', 'imagine'],
// ['paul', 'mccartney', 'yesterday'],
// ['george', 'harrison', 'taxman'],
// ['ringo', 'starr', 'walrus']]
Parameters:
| Name | Type | Attributes | Description |
|---|---|---|---|
arrayLeft |
Array | one array to combine with the array on the right |
|
arrayRight |
Array | another array to combine at the same indices on the left |
|
rest |
any |
<repeatable> |
additional arrays to combine |
Returns:
- Type
- Array.<Array>