JavaScript Array Manipulations
Practicing Datscy
Posted on August 31, 2024
Manipulating 2d, 3d, or 4d arrays in JavaScript are necessary for AI model training and data pre-processing analysis (text/image/audio/video).
Below are a few useful functions for array manipulation using pure JavaScript without matrix packages like Tensorflow.js.
Transpose of a 2d array
function transpose_2d_array(arr) {
var transpose_colNum = arr.length;
var transpose_rowNum = arr.at(0).length;
var transpose_arr = [];
for (var i=0; i<transpose_rowNum ; i++) {
const col = Array.from({ length: transpose_colNum }, (_, i) => 0);
transpose_arr.push(col);
}
for (var i=0; i<arr.length; i++) {
for (var j=0; j<arr.at(i).length; j++) {
transpose_arr[j][i] = arr[i][j];
}
}
return transpose_arr;
}
Print the Shape of an array
async function recur_func(arr) {
if (arr != undefined) {
return [arr[0], arr.length];
} else {
return arr;
}
}
async function shape(arr) {
var out = await recur_func(arr);
var shap = [out[1]];
var c = 0; // typically work with 4D arrays or less
while (out != undefined && c < 4) {
out = await recur_func(out[0]);
if (out != undefined) {
shap.push(out[1]);
}
c = c + 1;
}
return shap.slice(0, shap.length-1);
}
Exchange dimensions of an array
The tensorflow.js library and other numerical libraries have a reshape function, however, it is uncertain which dimensions maybe exchanged if two or more dimensions have the same size number. For example, reshaping a [2,1,2] into a [1,2,2] does not specify if the 0th dimension should be switch to the 1st or the 2nd dimension. In the function below, one can specify exactly which size should correspond with a particular dimension.
async function exchange_3d_dimensions(arr_3d, output_dims_index) {
// output_dims_index: [0,2,1] implying how to switch the dimension index of arr_3d, this is technically more precise because two dimension indexes could have the same size. So one is specifying exactly which dimension index to use for a particular dimension.
// output_dims_index specifies the [dimension index] of the desired output array
// [2,2,1] = [org_0th_dim, org_1st_dim, org_2nd_dim] => [2,1,2] = [org_0th_dim, org_2nd_dim, org_1st_dim] = [0,2,1]
// [0] List the original array location_values and values
var org_0th_dim = [];
var org_1st_dim = [];
var org_2nd_dim = [];
var val = [];
for (var i=0; i<arr_3d.length; i++) {
for (var j=0; j<arr_3d[0].length; j++) {
for (var k=0; k<arr_3d[0][0].length; k++) {
org_0th_dim.push(i);
org_1st_dim.push(j);
org_2nd_dim.push(k);
val.push(arr_3d[i][j][k])
}
}
}
// Need to transform output_dims_index, from index to dimensions
var dims_of_org_arr = [arr_3d.length, arr_3d[0].length, arr_3d[0][0].length];
var dims = output_dims_index.map((val, i) => { return dims_of_org_arr.at(val); });
// [1] Make the new shape array, filled with zeros
var desired_3d = await zeros(dims);
// Exchange notation for desired output index dimensions
var all = [org_0th_dim, org_1st_dim, org_2nd_dim];
var all_switched = output_dims_index.map((val, i) => { return all.at(val); });
org_0th_dim = all_switched.at(0);
org_1st_dim = all_switched.at(1);
org_2nd_dim = all_switched.at(2);
// [2] Fill in output shaped 3d array
var desired_0th_dim = dims.at(0);
var desired_1st_dim = dims.at(1);
var desired_2nd_dim = dims.at(2);
for (var i=0; i<desired_0th_dim; i++) {
for (var j=0; j<desired_1st_dim; j++) {
for (var k=0; k<desired_2nd_dim; k++) {
// cycle over the index of a for every i,j,k value
for (var ind=0; ind<org_0th_dim.length; ind++) {
if (org_0th_dim.at(ind) == i && org_1st_dim.at(ind) == j && org_2nd_dim.at(ind) == k) {
desired_3d[i][j][k] = val.at(ind);
}
}
}
}
}
return desired_3d;
}
// -----------------------------------------------
async function zeros(dims) {
// dims: [desired_0th_dim, desired_1st_dim, desired_2nd_dim]
var out = [];
if (dims.length == 1) {
var desired_0th_dim = dims.at(0);
out = Array.from({length: desired_0th_dim}, (val, ind) => { return 0; });
} else if (dims.length == 2) {
var desired_0th_dim = dims.at(0);
var desired_1st_dim = dims.at(1);
for (var i=0; i<desired_0th_dim; i++) {
var arr = Array.from({length: desired_1st_dim}, (val, ind) => { return 0; });
out.push(arr);
}
} else if (dims.length == 3) {
var desired_0th_dim = dims.at(0);
var desired_1st_dim = dims.at(1);
var desired_2nd_dim = dims.at(2);
for (var i=0; i<desired_0th_dim; i++) {
temp = [];
for (var j=0; j<desired_1st_dim; j++) {
var arr = Array.from({length: desired_2nd_dim}, (val, ind) => { return 0; });
temp.push(arr);
}
out.push(temp);
}
} else {
console.log('Enter an array of length 1, 2, or 3. (ie: [desired_0th_dim, desired_1st_dim, desired_2nd_dim])')
}
return out;
}
I hope these array utility functions will be helpful to someone.
Happy Practicing! š
š» GitHub | š· Practicing Datscy @ Dev.to | š³ Practicing Datscy @ Medium
References
- Inspiration for the creation of array functions: https://js.tensorflow.org/api/latest/
Posted on August 31, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.