1

How can I get data from an array by iterating two times inside it. For example I have a data set:

var data = [
    {"Fruits ":"Apples","Fresh":"12","Rotten":"5","Total":"17"},
    {"Fruits ":"Oranges","Fresh":"34","Rotten":"6","Total":"40"},
    {"Fruits ":"Strawberries","Fresh":"67","Rotten":"8","Total":"75"},
    {"Fruits ":"Bananas","Fresh":"23","Rotten":"5","Total":"28"}
]

First I would like to iterate on the right side and get all the keys until the end of the first object and then downwards so that I get all the values of the keys so I get

Expected Output

 [{ 'name': 'Fresh',
    'data': [12, 34, 67, 23]
    }, 
    {
    'name': 'Rotten',
    'data': [5, 6, 8, 5]
    },
    {
    'name': 'total',
    'data': [17, 40, 75, 28]
    }]

So far I have tried this:

    var categorie = []
    var seriesNames = []
    var series = []

    for(var i=0; i<data.length; i++){
      categorie.push(_.values(data[i])[0])
    }

    for(i=1; i<data.length; i++){
        seriesNames.push(_.keys(data[0])[i])
    }

But I am stuck how to get the data array and join it with seriesName. Live copy: plunker

EDIT The keys, values and data length are variable since I am dealing with dynamic data.

Imo
  • 1,455
  • 4
  • 28
  • 53
  • 1
    There's no JSON here. JSON is a *textual notation* for data exchange. [(More)](http://stackoverflow.com/a/2904181/157247) If you're dealing with JavaScript source code, and not dealing with a *string*, you're not dealing with JSON. – T.J. Crowder Jul 05 '16 at 14:28

10 Answers10

4

You could use a group array and use it for the right grouping in the result array.

var data = [{ "Fruits ": "Apples", "Fresh": "12", "Rotten": "5", "Total": "17" }, { "Fruits ": "Oranges", "Fresh": "34", "Rotten": "6", "Total": "40" }, { "Fruits ": "Strawberries", "Fresh": "67", "Rotten": "8", "Total": "75" }, { "Fruits ": "Bananas", "Fresh": "23", "Rotten": "5", "Total": "28" }],
    groups = ["Fresh", "Rotten", "Total"],
    result = [];

data.forEach(function (a) {
    groups.forEach(function (b, i) {
        result[i] = result[i] || { name: b, data: [] };
        result[i].data.push(+a[b]);
    });
});

console.log(result);

Just a slightly changed proposal for dynamic properties. It takes only properties with finite numbers.

var data = [{ "Fruits ": "Apples", "Fresh": "12", "Rotten": "5", "Total": "17" }, { "Fruits ": "Oranges", "Fresh": "34", "Rotten": "6", "Total": "40" }, { "Fruits ": "Strawberries", "Fresh": "67", "Rotten": "8", "Total": "75" }, { "Fruits ": "Bananas", "Fresh": "23", "Rotten": "5", "Total": "28" }],
    result = [];

data.forEach(function (a) {
    Object.keys(a).forEach(function (k) {
        if (isFinite(a[k])) {
            if (!this[k]) {
                this[k] = { name: k, data: [] };
                result.push(this[k]);
            }
            this[k].data.push(a[k]);
        }
    }, this);
}, Object.create(null));

console.log(result);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
2

Use array.prototype.map:

var arr = [
{"Fruits ":"Apples","Fresh":"12","Rotten":"5","Total":"17"},
{"Fruits ":"Oranges","Fresh":"34","Rotten":"6","Total":"40"},
{"Fruits ":"Strawberries","Fresh":"67","Rotten":"8","Total":"75"},
{"Fruits ":"Bananas","Fresh":"23","Rotten":"5","Total":"28"}
];

var newArr = ["Fresh", "Rotten", "Total"].map(function(item) {
  return {
    name: item,
    data: arr.map(function(innerItem) {
      return parseInt(innerItem[item],10);
    })
  }
});

console.log(newArr);
Amir Popovich
  • 29,350
  • 9
  • 53
  • 99
2

You can try something like this:

You can have a list of keys that needs to be excluded and process keys based on this list.

var data = [{"Fruits ":"Apples","Fresh":"12","Rotten":"5","Total":"17"},
{"Fruits ":"Oranges","Fresh":"34","Rotten":"6","Total":"40"},
{"Fruits ":"Strawberries","Fresh":"67","Rotten":"8","Total":"75"},
{"Fruits ":"Bananas","Fresh":"23","Rotten":"5","Total":"28"}
]
var keys_to_exclude = ["Fruits"];
var _tmp = {};

data.forEach(function(o) {
  for (var k in o) {
    if (keys_to_exclude.indexOf(k.trim()) < 0) {
      _tmp[k] = _tmp[k] || [];
      _tmp[k].push(o[k]);
    }
  }
});

var result = Object.keys(_tmp).map(function(k) {
  return {
    name: k,
    data: _tmp[k]
  }
});

document.getElementById("r").innerHTML = JSON.stringify(result, 0, 4);
<pre id="r"></pre>
Rajesh
  • 24,354
  • 5
  • 48
  • 79
1

Since you are using underscore it actually is a pretty simple map over the collection.

First, find keys of the objects.

Later, with map you can obtain the required property of the object.

var keys = _.keys(data[0]).reverse()
keys = _.without(keys, keys[0]) 


var c = _.map(keys, function(k) {
  return {
    name: k,
    data: _.map(data, k)
  };
});

Also with a plunker: https://plnkr.co/edit/KtJPMu?p=preview

Atais
  • 10,857
  • 6
  • 71
  • 111
  • Thanks this is very close to what I was looking for the only problem is that It gives {"name":"Fruits ","data":["Apples","Oranges","Strawberries","Bananas"] which I do not want I just want data for fresh, rotten and total – Imo Jul 05 '16 at 14:43
  • @Imo well simply remove it from the keys array first. I do not know if its 1st index or static name, see update. – Atais Jul 05 '16 at 14:45
0

Here's one way to do it:

var output = data.reduce(function(acc, cur) {
    for(var k in cur) {
        if (!cur.hasOwnProperty(k) || k === 'Fruits ') {
            continue;
        }
        var container = acc.filter(function(item) {
            return item.name === k;
        })[0];
        if (!container) {
            container = {
                name: k,
                data: []
            };
            acc.push(container);
        }
        container.data.push(cur[k])
    }
    return acc;
},[]);
daf
  • 1,289
  • 11
  • 16
0

I suggest you work with the output objects directly and add them to an array later:

var data = [{"Fruits ": "Apples","Fresh": "12","Rotten": "5","Total": "17"}, {"Fruits ": "Oranges","Fresh": "34","Rotten": "6","Total": "40"}, {"Fruits ": "Strawberries","Fresh": "67","Rotten": "8","Total": "75"}, {"Fruits ": "Bananas","Fresh": "23","Rotten": "5","Total": "28"}];

var fresh = {name: 'Fresh', data: []};
var rotten = {name: 'Rotten', data: []};
var total = {name: 'Total', data: []};

data.forEach(function(fruit) {
  fresh.data.push(+fruit.Fresh);
  rotten.data.push(+fruit.Rotten);
  total.data.push(+fruit.Total)
});

var output = [fresh, rotten, total];
console.log(output);
TimoStaudinger
  • 41,396
  • 16
  • 88
  • 94
0

Try this:

var result = [
  {'name':'Fresh', 'data':[]},
  {'name':'Rotten', 'data':[]},
  {'name':'Total', 'data':[]}
];

for (d of data) {
  result[0].data.push(d['Fresh']);
  result[1].data.push(d['Rotten']);
  result[2].data.push(d['Total']);
}

Output looks like this:

[{"name":"Fresh","data":["12","34","67","23"]},
{"name":"Rotten","data":["5","6","8","5"]},
{"name":"Total","data":["17","40","75","28"]}]
Philipp
  • 4,180
  • 7
  • 27
  • 41
0

I would recommend @nina-scholz 's answer above. However if someone wants to see how exactly it's done in simple JS, refer below code:

var data = [{"Fruits ":"Apples","Fresh":"12","Rotten":"5","Total":"17"},
{"Fruits ":"Oranges","Fresh":"34","Rotten":"6","Total":"40"},
{"Fruits ":"Strawberries","Fresh":"67","Rotten":"8","Total":"75"},
{"Fruits ":"Bananas","Fresh":"23","Rotten":"5","Total":"28"}]

//list of items that needs to be in the final list
var categorie = ["Fresh", "Rotten", "Total"];
var seriesNames = {};
var series = [];

// iterate through the initial array
for(var i=0; i<data.length; i++){
  // iterate through the category
  for(var j=0; j<categorie.length; j++) {
    if(data[i].hasOwnProperty(categorie[j])) {
        // seriesNames will hold the category name and corresponding value will be an array of values(total, rotten, fresh) from all objects
        if(seriesNames[categorie[j]]) { // array already exists
            var arr = seriesNames[categorie[j]];
            arr.push(data[i][categorie[j]]);
        } else { // create a new array
            seriesNames[categorie[j]] = new Array();
        }
    }
  }
}

// create the required output object
for(var attr in seriesNames) {
    var obj = {};
    obj['name'] = attr;
    obj['data'] = seriesNames[attr];
    series.push(obj);
}

// expected output is in series.
console.debug(series);
Anurag Sinha
  • 1,014
  • 10
  • 17
0
var i, j, ref, output = { Fresh: [], Rotten: [], Total: [] }; //ignore anything that isn't here.
for (i of data) {
  for (j in i) {
    if (typeof (ref = output[j]) !== 'undefined')
      ref.push(i[j]);
  }
}

output looks like this (JSON)

{
  "Fresh":["12","34","67","23"],
  "Rotten":["5","6","8","5"],
  "Total":["17","40","75","28"]
}

This isn't quite the format you want, so we can run through it one more time:

var output2 = [];
for (k in output) {
  output2.push({ name: k, data: output[k] });
}

output2 should now look like you wanted (JSON)

[{
  "name":"Fresh",
  "data":["12","34","67","23"]
},{
  "name":"Rotten",
  "data":["5","6","8","5"]
},{
  "name":"Total",
  "data":["17","40","75","28"]
}]

To polish it off, we can throw it all together in a function

function nameMeSomething(data) {
  var i, j, k, l, m = [], n = { Fresh: [], Rotten: [], Total: [] }; //ignore anything that isn't here.
  for (i of data) for (j in i) if (typeof (l = n[j]) !== 'undefined') l.push(i[j]);
  for (k in n) m.push({ name: k, data: m[k] });
  return m
}
JD Byrnes
  • 783
  • 6
  • 17
0

My solution gets all keys with numeric values (which is more than PO's terms) and completely chained as one row answer.

var data = [{ "Fruits ": "Apples", "Fresh": "12", "Rotten": "5", "Total": "17" }, { "Fruits ": "Oranges", "Fresh": "34", "Rotten": "6", "Total": "40" }, { "Fruits ": "Strawberries", "Fresh": "67", "Rotten": "8", "Total": "75" }, { "Fruits ": "Bananas", "Fresh": "23", "Rotten": "5", "Total": "28" }];

var result = Object.keys(data[0])
  .filter(k => !isNaN(data[0][k]))
  .map(k => ({
    name: k,
    data: data.map(d => d[k])
  }));

console.log(result);
Morteza Tourani
  • 3,506
  • 5
  • 41
  • 48