Combining and restructuring multidimensional arrays in Javascript: A step-by-step guide

I'm struggling with transforming a multidimensional array in JavaScript. Here is an example of the input array:

[
[['a',1],['b',2],['c',3]],
[['a',4],['d',2],['c',3],['x',5]],
[['a',1],['c',2],['f',3],['x',1],['o',7]]
]

The desired output should look like this:

[
["a",1,4,1],
["b",2,null,null],
["c",3,3,2],
["d",null,2,null],
["x",null,5,1],
["f",null,null,3],
["o",null,null,7]]
]

Basically, I need to merge parts of the array based on the first element and fill any gaps with "null". For instance, the pair with "x" has values 5 and 1 in the second and third rows, so it should be ["x",null,5,1].
Every line represents charting data series after optimization, and maintaining the correct position of values is crucial.

Currently, I have managed to format the data as expected but I'm struggling to add the "null" values in the correct positions.

Below is my code:

var cubes = [
        [['a',1],['b',2],['c',3]],
        [['a',4],['d',2],['c',3],['x',5]],
        [['a',1],['c',2],['f',3],['x',1],['o',7]]
        ];
var out = [];
for (var i=0; i<cubes.length; i++) {
    for (var j=0; j<cubes[i].length; j++) {
        out.push(cubes[i][j]);
        for (var x=0; x<out.length-1; x++) {
         if (out[x][0] == cubes[i][j][0]) {
            out[x].push(cubes[i][j][1]);
            out.pop();
         }
        }
    }
}
console.log(out);

This code gives me the following output:

[
["a",1,4,1],
["b",2],
["c",3,3,2],
["d",2],
["x",5,1],
["f",3],
["o",7]
]

Moreover, I have a hunch that there might be a simpler way to achieve this, possibly using map/reduce functions, but my brain seems to be frozen today :/ Any suggestions?

Check out the JSFiddle code here

Answer №1

You asked for a simple solution, so here's an illustration of JavaScript's latest shortcuts for array operations:

    var test = [
      [['a',1],['b',2],['c',3]],
      [['a',4],['d',2],['c',3],['x',5]],
      [['a',1],['c',2],['f',3],['x',1],['o',7]]
    ];
    var result = [];
    // The maximum possible value count will be updated
    var max_values = 0;
    
    // Iterate over each row in input
    test.forEach(function(row, index) {// Index is used to properly pad null from right
      //Iterate over each pair of letter and number
      row.forEach(function(cell) {//cell is one of ['x', 0]
        var groupName = cell[0]; //a, b, c ...
        // Find a group in results
        var entry = result.find(function(newRow) {
          return newRow[0] == groupName;
        });
        // If no group was found, create a group and add it to results
        if(!entry) {
            entry = [groupName];
            result.push(entry);
        }
        // Left-pad nulls
        while(entry.length-1<index)
            entry.push(null);
        // Push the value
        var count = entry.push(cell[1]);
        // Update max count number
        max_values = Math.max(max_values, count);
        // Second pass - fill in `null` so that all entries are the same length
    result.forEach(function(row) {
      // Pad until all rows are as long as the longest one
      while(row.length<max_values)
        row.push(null);
    });
    //Debug
    console.log(result);
    document.write("<pre>"+result.join("\n")+"</pre>");

Featuring: .forEach and .find. Note that find is really new and neither find neither forEach appear in older browsers.

I win!

Answer №2

Arranging the main keys is necessary, resulting in a sorted list of final outcomes.

let keys = [];
// Sorting cubes and creating an array of `keys`
cubes.forEach(function(cube){
    cube.sort((a, b) => {
       return a[0] > b[0];
    }).forEach(function(subArr){
        if(keys.indexOf(subArr[0]) === -1 ){
            keys.push(subArr[0]);
        }
    });
});
// Sorting keys
keys.sort();
// Mapping a new array based on sorted cubes and keys
let out = keys.map(function(key, idx){
    let newArr = [key];

    cubes.forEach(function(cube){
        let match = cube.filter(function(subArr){
            return subArr[0] === key;
        });
        newArr.push( match.length ? match[0][1] : null)
    });

    return newArr

});

Output:

[    
    [ "a", 1, 4, 1 ]
    [ "b", 2, null, null ]
    [ "c", 3, 3, 2 ]
    [ "d", null, 2, null ]
    [ "f", null, null, 3 ]
    [ "o", null, null, 7 ]
    [ "x", null, 5, 1 ]    
]

View DEMO

Answer №3

To efficiently organize your arrays by key and create the final result, you can use a temporary object to store the data first.

var index = 0;
var result = [];
var temp = {};
var cubes = [
  [['a',1],['b',2],['c',3]],
  [['a',4],['d',2],['c',3],['x',5]],
  [['a',1],['c',2],['f',3],['x',1],['o',7]]
];

for(var i = 0; i < cubes.length; i++) {
  var row = cubes[i];
  row.forEach(function(item) {
    var name = item[0];
    var value = item[1];
    
    if (!temp[name]) {
      temp[name] = {
        index: index, //store index to maintain order in result
        values: new Array(cubes.length)
      };
      index++;
    }
    
    temp[name]['values'][i] = value;
  });
}

for(var name in temp) {
  var a = [];
  a.push(name);
  for(var i = 0; i < cubes.length; i++) {
    if (temp[name]['values'][i])
      a.push(temp[name]['values'][i]);
    else
      a.push(null);
  }
  result[temp[name].index] = a;
}

console.log(result);
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What are the differences between a Chrome app and extension? Is there any other way to access the tabs currently open in your

I need to develop an app that can access the tabs a user has open, but I'm struggling to find a way to do so without having my app run in Chrome itself. Creating an extension restricts the UI significantly, which is problematic since my app requires a ...

having trouble transferring the password field in PHP to phpMyAdmin

My HTML form collects the user's first name, last name, username, and password. I am trying to upload this data to my local phpMyAdmin, but I'm facing an issue with storing the password in the database. Below is my HTML code: <input type="te ...

An uncaught runtime error has occurred: TypeError - subSector.map is not a valid function

I'm encountering a challenge when attempting to map through JSON data retrieved from a fictitious API. The process works smoothly when there is more than one data item, but I encounter an error when there is only a single object. Below is the code sn ...

Is it possible to retrieve and display an object from an API using its unique ID?

I created a straightforward application. The main page displays a list of movies fetched using an API, and upon clicking on a particular movie, it leads to a new page with detailed information about that movie. On the details page, another API call is ma ...

The TypeScript Promise error codes TS2304 and TS2529 are causing confusion among

I came across the code below: function asyncTask(): Promise<string> { return new Promise<string>(resolve => resolve); } This code resulted in the following error: TS2304: cannot find name 'Promise' To address this issue, ...

How to automatically select the first item in a populated dropdown list using Vue JS

My HTML select element is populated with options from a server, but when using v-model, it initially selects an empty option instead of the first one. I came across a solution on a post which suggests selecting the first option manually, but since the dat ...

Reproducing a table row

Here is the table structure I am working with: <table id="customFields" class="table table-bordered table-hover additionalMargin alignment"> <thead> <tr> <th colspan="2"></th> <th>Some Title</ ...

Every time I hover, my jQuery code keeps repeating the hover effect

I am currently facing an issue that has me stumped on finding a solution. The problem arises when I hover over the .div multiple times, the animation just doesn't stop and keeps running continuously. What I aim for is to have the .hidden element fad ...

What is the best way to simulate our services for controller testing?

Currently delving into angular js and experimenting with testing a controller. Here is the service I am using: angular.module('test'){ service.getAllServices = function() { var fullPath = url var deferre ...

Passing PHP array to JavaScript and selecting random images from the array

Check out my PHP script below: <?php $all_images = glob("Images/Classes/{*.png, *.PNG}", GLOB_BRACE); echo json_encode($all_images); shuffle($all_images); ?> Here's the JavaScript code I'm using: functio ...

Performing a double iteration on a JSON array using nested foreach loops to associate each index with its

I have successfully decoded a JSON array +"productINF": {#1260 ▼ +"product": {#1011 ▼ +"productCode": "123" +"productType": {#999 ▼ +"count": 3.0 +"desc": "Block" } } } +"price": {#1267 ▼ +"02": "470.00" } Now, I am ...

Firestore data displaying as null values

Recently, I encountered CORS errors while polling the weather every 30 seconds in my program. Upon investigating, I discovered that the city and country were being interpreted as undefined. To fetch user data from my users' table, I utilize an Axios ...

Tips for determining the presence of a query string value using JavaScript

Is there a way to detect the presence of q= in the query string using either JavaScript or jQuery? ...

Utilizing array_map to swap out spaces among letters

As I convert a string with comma-separated values into an array, I encounter certain issues. The values in the string sometimes have spaces between characters that need to be replaced by dashes for URL-friendliness. For instance, "hello world" should becom ...

Utilize Javascript to convert centimeters into inches

Can anyone help me with a JavaScript function that accurately converts CM to IN? I've been using the code below: function toFeet(n) { var realFeet = ((n*0.393700) / 12); var feet = Math.floor(realFeet); var inches = Math.round(10*((realFeet ...

Issue with JQuery delay functionality not activating correctly upon clicking an <a> tag

When I click on an <a> tag, I want to display a div and wait for 10 seconds before redirecting. However, the div is currently being shown immediately without waiting. Here is the HTML code: <a class="clickHereToDisplay" href="http://www.google.c ...

What is the process for configuring environmental variables within my client-side code?

Is there a reliable method to set a different key based on whether we are in development or production environments when working with client-side programs that lack an inherent runtime environment? Appreciate any suggestions! ...

The concept of immutability is crucial when utilizing a for-in loop to append an object to an array

Within my code, I have a nested loop structure consisting of a for of with a for in loop inside it. This setup retrieves information from a Neo4J database. By utilizing the Object.assign method, I am able to transfer a property from the fetched object into ...

Error encountered in my JavaScript file - Unexpected Token < found on line 1 of the loadash.js script

I am right at the end of creating a sample dashboard with charts using dc.js, but I have hit a roadblock with one error remaining. This error is causing an issue. Unexpected token < on line 1 for loadash.js. The loadash.js file is valid, but for som ...

Show data from a Node.js server in its original format within an AngularJS application

Currently, I am using the angular fullstack generator to develop a web application. One issue I am facing is sending file data from the Node.js server to display on the front end. The problem arises because the data is being sent in an unformatted manner, ...