DEV Community

Cover image for JavaScript Array Manipulations
Practicing Datscy
Practicing Datscy

Posted on • Updated on

JavaScript Array Manipulations

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;
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

I hope these array utility functions will be helpful to someone.

Happy Practicing! 👋

💻 GitHub | 🌷 Practicing Datscy @ Dev.to | 🌳 Practicing Datscy @ Medium

References

  1. Inspiration for the creation of array functions: https://js.tensorflow.org/api/latest/

Top comments (0)