skip to Main Content

I would like to save a two dimensional array consisting of one column of indicators (string) and one column of values (integer our double) in a file that has JSON format.
It somehow works but not the way I finally want it. I don’t understand the problem why I get the result twice. Any idea around?
I am search the web for days and didn’t find yet any answer that helped – or I didn’t understand the answer. And yes it is client-side.

The function currently looks like this:

function array2JSON(fname) {

    var totals = [
        ["ID_1", "ID_2", "ID_3", "ID_4", "ID_5","ID_6","ID_7","ID_8"],
        [171.82, 54.0, 2.33, 1234.2, 1.23, 45.67, 0.98,0.123]
    ]; 
    
    var totalsObj =  totals.reduce((map, totals) => { 
        
        
        map.totals.push(  {identifier: totals, values: totals}); 
        
        
        return map;
    }, { totals: []});

    var myBlobFile = new Blob([JSON.stringify(totalsObj,null,4)], { 
       type: 'text/json;charset=utf-8' 
    });
    
    var url = window.URL || window.webkitURL;
    
    var temp_link = document.createElement('a');
    temp_link.download = fname+".json";
    temp_link.href = URL.createObjectURL(myBlobFile);
    //temp_link.hidden = true;

    

    // This link should not be displayed
    
    document.body.appendChild(temp_link);
    temp_link.click();
    document.body.removeChild(temp_link);
}

What I get is this:

{ totals: 
  [ { identifier : [ 'ID_1', 'ID_2', 'ID_3', 'ID_4', 'ID_5', 'ID_6', 'ID_7', 'ID_8' ] 
    , values     : [ 'ID_1', 'ID_2', 'ID_3', 'ID_4', 'ID_5', 'ID_6', 'ID_7', 'ID_8' ] 
    } 
  , { identifier : [ 171.82,     54,   2.33, 1234.2,   1.23,  45.67,   0.98,  0.123 ] 
    , values     : [ 171.82,     54,   2.33, 1234.2,   1.23,  45.67,   0.98,  0.123 ] 
} ] } 

3

Answers


  1. Your code deliberately builds the structure you’re ending up with.

    The .reduce() call will invoke the callback twice, once for each row of your 2-D totals array. On the first call, the value of the parameter "totals" will be the "ID" row of the outer totals 2-D array. On the second call, it will be the second row, with the numbers.

    So the callback:

    (map, totals) => { 
        map.totals.push(  {identifier: totals, values: totals}); 
        return map;
    }
    

    adds the value of the parameter "totals" to an object, twice. The first time, you get an object with the "ID" strings (twice), and the second time you get an object with the numbers (twice).

    Your question does not explain what you want, but if (for example) you wanted an array like this:

    [
        ["ID_1", 171.82],
        ["ID_2", 54],
        // ...
    ]
    

    then you could get that easily with a simple loop:

        let result = [];
        for (let i = 0; i < totals[0].length; i++)
            result.push([totals[0][i], totals[1][i]]);
    

    edit from your added comment, it’s vastly easier:

        let result = { totals: {
            identifier: totals[0],
            value: totals[1]
        } };
    
    Login or Signup to reply.
  2. The problem is that you do not create the structure you want in your code with the reduce() function.

    To get the output described by you in the comment there’s no need to loop at all. You can just create a new object with the specified structure:

    const totals = [
      ["ID_1", "ID_2", "ID_3", "ID_4", "ID_5", "ID_6", "ID_7", "ID_8"],
      [171.82, 54.0, 2.33, 1234.2, 1.23, 45.67, 0.98, 0.123],
    ];
    
    const [identifiers, values] = totals;
    const result = {
      totals: [{
        identifier: identifiers,
        values: values,
      }]
    };
    
    console.log(JSON.stringify(result, null, 4));
    /* Stackoverflow: show only console */
    .as-console-wrapper {
      max-height: 100% !important;
      top: 0;
    }

    I am using array destructuring here. Instead of that you could also access the array by using indices.

    If you want to ensure immutability (although you’re not writing/ changing anything here) you can of course also copy the arrays e.g. by using the spread syntax like [...identifiers] (or using identifiers.slice()) and then reference the copies in your new object.

    FYI: I am not sure why you want totals to be an array (or why it’s even in plural form) if you only have one entry in the array. You could easily make that an object.

    Login or Signup to reply.
  3. For generating your willing output you don’t have to use reduce() function

    Just use below code:

    var totalsObj = {
        totals: [{
            identifier: totals[0],
            values: totals[1]
        }]
    };
    
    finalJsonString = JSON.stringify(totalsObj,null,4);
    

    And your final code should be like this:

    function array2JSON(fname) {
        var totals = [
            ["ID_1", "ID_2", "ID_3", "ID_4", "ID_5", "ID_6", "ID_7", "ID_8"],
            [171.82, 54.0, 2.33, 1234.2, 1.23, 45.67, 0.98, 0.123],
        ];
        /* updated code */
        var totalsObj = {
            totals: [
                {
                    identifier: totals[0],
                    values: totals[1],
                },
            ],
        };
    
        var myBlobFile = new Blob([JSON.stringify(totalsObj, null, 4)], {
            type: "text/json;charset=utf-8",
        });
    
        var url = window.URL || window.webkitURL;
    
        var temp_link = document.createElement("a");
        temp_link.download = fname + ".json";
        temp_link.href = URL.createObjectURL(myBlobFile);
        //temp_link.hidden = true;
    
        // This link should not be displayed
    
        document.body.appendChild(temp_link);
        temp_link.click();
        document.body.removeChild(temp_link);
    }
    

    That’s it.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search