huan feng
huan feng

Reputation: 8623

JS data manipulation

I have a data like this: (The real record has far more than this)

year    type    quantity
2011    A       1000
2012    B       1000
2012    C       1000
2012    A       1000
2015    A       1000

JSON:

[{year:2011, type:A, quantity:1000},...]

and i want to have the result like this: (I want every year and every type has a record there)

year    type    quantity
2011    A       1000
2011    B       -
2011    C       -
2012    A       1000
2012    B       1000
2012    C       1000
2015    A       1000
2015    B       -
2015    C       -

Is there any good way to do this? underscore solution is also welcomed!

Upvotes: 3

Views: 87

Answers (3)

charlietfl
charlietfl

Reputation: 171679

Vanilla JS, includes final sort

var yrs = [], types = [], tmp={};

data.forEach(function(item){
     // create arrays of years and types
     if(yrs.indexOf(item.yr) === -1){
        yrs.push(item.yr);
    }
    if(types.indexOf(item.type) === -1){
        types.push(item.type);
    }
    // temp object used in next step to look for holes
    tmp[item.yr + item.type] = true;
});

yrs.forEach(function(yr){
    types.forEach(function(type){
        // fill in holes
        if(!tmp.hasOwnProperty(yr+type)){
           data.push({yr: yr, type: type, qty: 0});
         }
    })
});

data.sort(function(a,b){
    return b.yr === a.yr ? a.type > b.type : +a.yr - +b.yr
});

DEMO

Upvotes: 1

davcs86
davcs86

Reputation: 3935

A bit optimized version with jquery

var source = [{year:2011, type: 'A', quantity:100},{year:2012, type: 'B', quantity:200}],
    product = [],
    types = {}, 
    years = {}, 
    quantities = {};

$.each(source, function(i){
    var type = source[i].type, 
        year = source[i].year;
    types[type]= true;
    years[year]= true;
    if (typeof quantities[type] == "undefined")
        quantities[type] = {};
    quantities[type][year] = source[i].quantity;
});

$.each(types, function(type){
    var qts = quantities[type];
    $.each(years, function(year){
        var value = "-";
        if (typeof qts[year] != "undefined")
            value = qts[year];
        product.push({year:year, type: type, quantity:value});
    });
});

console.log(product);

Saves time by extracting the types and years in one loop, and doesn't store repeated values (so there's no need of .unique).

JSFiddle demo

Upvotes: 1

Miyuru Ratnayake
Miyuru Ratnayake

Reputation: 456

Hope this will work with underscore:

var source = [{year: "2011", type: "A",...} ...];
var years = _.uniq(_.map(source , function(item){
    return item.year;
}))

var types = _.uniq(_.map(source , function(item){
    return item.type;
}))

var result = [];
_.each(years, function(yearItem){
    _.each(types, function(typeItem){
      var resultItem = _.find(source, function(item){
            return item.year === yearItem && item.type === typeItem;
        })
       if(undefined === resultItem){
             resultItem = {
               year: yearItem,
               type: typeItem,
               quantity: "-"
             };{}
       } 
           result.push(resultItem);


    })
})

Upvotes: 1

Related Questions