GuitarExtended
GuitarExtended

Reputation: 827

Array and object copy in Javascript

I have the following data :

[
    {"date":1900,"data":[
        {"name":"Blackbird","value":0},
        {"name":"Seagull","value":1},
        {"name":"Sparrow","value":0}
    ]},
    {"date":1910,"data":[
        {"name":"Owl","value":1}
    ]},
    {"date":1920,"data":[
        {"name":"Eagle","value":0},
        {"name":"Albatross","value":2}
    ]}
]

I need to make an incremental array of arrays from it. It should look something like this :

[
    [
        {"name":"Blackbird","value":0,"date":1900},
        {"name":"Seagull","value":1,"date":1900},
        {"name":"Sparrow","value":0,"date":1900}
    ],
    [
        {"name":"Blackbird","value":0,"date":1910},
        {"name":"Seagull","value":1,"date":1910},
        {"name":"Sparrow","value":0,"date":1910},
        {"name":"Owl","value":1,"date":1910}
    ],
    [  
        {"name":"Blackbird","value":0,"date":1920},
        {"name":"Seagull","value":1,"date":1920},
        {"name":"Sparrow","value":0,"date":1920},
        {"name":"Owl","value":1,"date":1920},
        {"name":"Eagle","value":0,"date":1920},
        {"name":"Albatross","value":2,"date":1920}
    ]
]

No matter what I have tried, I always end up with all the dates I add to the objects being equal to the last value (1920 here). I understand that the objects are copied by reference only. I have tried using array.map() (like in the answer given here, but my question was not formulated right), but I still get the same problem.

EDIT Here's one example of code I've tried :

        var temp = [];
        var b = data.map(function(c, index, main) {
            var year = c.date;
            temp = [];
            main.slice(0, index + 1).map(function(d){
                var t = d.data.map(function(e){
                    e.date = year;
                    return e;
                });
                temp = temp.concat(t);
            });
            return temp;
        });
        console.log(b);

Upvotes: 2

Views: 65

Answers (3)

adeneo
adeneo

Reputation: 318162

Use map, iterate over the inner array, and set the date property to each object etc.

var data = [
    {"date":1900,"data":[
        {"name":"Blackbird","value":0},
        {"name":"Seagull","value":1},
        {"name":"Sparrow","value":0}
    ]},
    {"date":1910,"data":[
        {"name":"Owl","value":1}
    ]},
    {"date":1920,"data":[
        {"name":"Eagle","value":0},
        {"name":"Albatross","value":2}
    ]}
]

data = data.map(function(obj, i, arr) {
    var o = [];
    
    arr.slice(0, i).forEach(function(item) {
        item.data.forEach(function(data) {
            o.push(Object.assign({}, data))
        });
    });
    
    return o.concat(obj.data.map(function(item) { item.date = obj.date; return item }));
});

document.body.innerHTML = '<pre>' + JSON.stringify(data, null, 4) + '</pre>';

Object.assign with polyfill

Upvotes: 0

Marcos Casagrande
Marcos Casagrande

Reputation: 40374

Here's a working example:

You need to clone the object in order to "break" the reference.

var data = [
        {
          "date":1900,
           "data":[
            {"name":"Blackbird","value":0},
            {"name":"Seagull","value":1},
            {"name":"Sparrow","value":0}
          ]
        },
        {
          "date":1910,
          "data":[
            {"name":"Owl","value":1}
          ]
        },
        {
          "date":1920,
          "data":[
            {"name":"Eagle","value":0},
            {"name":"Albatross","value":2}
          ]
        }
    ];

    var incremental = [];
    var dataHistory = null;

    for(i = 0; i < data.length; i++){
      var temp = dataHistory ? dataHistory.slice() : []; //.slice to clone array

      //Replace all values with current date.
      for(var j = 0; j < temp.length; j++){
        temp[j] = JSON.parse(JSON.stringify(temp[j])); //Clone object
        temp[j].date = data[i].date;
      }
      
      //Add current date to object.
      for(var j = 0; j < data[i].data.length; j++){
         var aux = {
           name: data[i].data[j].name,
           value: data[i].data[j].value,
           date: data[i].date
         };
        
         temp.push(aux);
      }
      
      dataHistory = temp;
      incremental.push(temp);
    }

document.body.innerHTML = '<pre>' + JSON.stringify(incremental, null, 4) + '</pre>';

If you're using jQuery you can replace:

temp[j] = JSON.parse(JSON.stringify(temp[j]));

With:

temp[j] = $.extend({}, temp[j]);

Upvotes: 1

Peter Janin
Peter Janin

Reputation: 1

Try this one:

var data = [
    {"date":1900,"data":[
        {"name":"Blackbird","value":0},
        {"name":"Seagull","value":1},
        {"name":"Sparrow","value":0}
    ]},
    {"date":1910,"data":[
        {"name":"Owl","value":1}
    ]},
    {"date":1920,"data":[
        {"name":"Eagle","value":0},
        {"name":"Albatross","value":2}
    ]}
];

var result = data.map(function(item) {
  var replacement = [];
  for (var key in item.data) {
     var subItem = item.data[key];
     subItem.date = item.date;
     replacement.push(subItem); 
  }
  return replacement;
});

document.body.innerHTML = '<pre>' + JSON.stringify(result, null, 3) + '</pre>';

Upvotes: 0

Related Questions