egurb
egurb

Reputation: 1216

How Do I Pivot An Array Of Objects in JavaScript?

I have an array of object which I need to convert to a table (kind of pivoting the data). Saying this I need to get another array of objects with the unique titles which have nested arrays of object with pairs of the values. Could you please take a look into this and help with achiving what I need? Please see the original and the desired array below:

Original Array:

[
{title: "Title1", value1: "value1", value2: "value2"},
{title: "Title2", value1: "value1", value2: "value2"},
{title: "Title1", value1: "value1", value2: "value2"},
{title: "Title3", value1: "value1", value2: "value2"},
{title: "Title2", value1: "value1", value2: "value2"},
{title: "Title1", value1: "value1", value2: "value2"},
{title: "Title3", value1: "value1", value2: "value2"},
{title: "Title1", value1: "value1", value2: "value2"},
]

Desired result:

[
{title: "Title1", values: [{value1: "value1"}, {value2: "value2"}]},
{title: "Title2", values: [{value1: "value1"}, {value2: "value2"}]},
{title: "Title3", values: [{value1: "value1"}, {value2: "value2"}]},
]

Thanks if advance for any suggestions.

Upvotes: 2

Views: 8232

Answers (3)

Nina Scholz
Nina Scholz

Reputation: 386620

You could use a hash table for grouping as thisArg with Array#forEach.

var data = [{ title: "Title1", value1: "value1", value2: "value2" }, { title: "Title2", value1: "value1", value2: "value2" }, { title: "Title1", value1: "value1", value2: "value2" }, { title: "Title3", value1: "value1", value2: "value2" }, { title: "Title2", value1: "value1", value2: "value2" }, { title: "Title1", value1: "value1", value2: "value2" }, { title: "Title3", value1: "value1", value2: "value2" }, { title: "Title1", value1: "value1", value2: "value2" }],
    grouped = [];

data.forEach(function (a) {

    // check if title is not in hash table
    if (!this[a.title]) {

        // if not, create new object with title and values array
        // and assign it with the title as hash to the hash table
        this[a.title] = { title: a.title, values: [] };

        // add the new object to the result set, too
        grouped.push(this[a.title]);
    }

    // create a new object with the other values and push it
    // to the array of the object of the hash table
    this[a.title].values.push({ value1: a.value1, value2: a.value2 });
}, Object.create(null)); // Object.create creates an empty object without prototypes

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 4

ste2425
ste2425

Reputation: 4766

A simple array reduce may be of help

let data = [{
  title: "Title1",
  value1: "value1",
  value2: "value2"
}, {
  title: "Title2",
  value1: "value1",
  value2: "value2"
}, {
  title: "Title1",
  value1: "value1",
  value2: "value2"
}, {
  title: "Title3",
  value1: "value1",
  value2: "value2"
}, {
  title: "Title2",
  value1: "value1",
  value2: "value2"
}, {
  title: "Title1",
  value1: "value1",
  value2: "value2"
}, {
  title: "Title3",
  value1: "value1",
  value2: "value2"
}, {
  title: "Title1",
  value1: "value1",
  value2: "value2"
}];

let pivoted = data.reduce((prev, cur) => {
  let existing = prev.find(x => x.title === cur.title);

  if (existing)
    existing.values.push(cur)
  else
    prev.push({
      title: cur.title,
      values: [cur]
    });

  return prev;
}, []);

console.log(pivoted);

API's used

Reduce

Find

This could then be adapted to pivot by any field you desire, it would need error handling adding if that field does not exist however:

let pivotBy = (key, data) => data.reduce((prev, cur) => {
  let existing = prev.find(x => x[key] === cur[key]);

  if (existing) {
    existing.values.push(cur);
  } else {
    let toInsert = {
        values: [cur]
    }

    toInsert[key] = cur[key];

    prev.push(toInsert);
  }

  return prev;
}, []);

EDIT I misinterpreted your desired output format, however the reduce approach could be modified to fulfill that requirement.

Upvotes: 6

xale94
xale94

Reputation: 424

    var originalArray = [
      {title: "Title1", value1: "value1", value2: "value2"},
      {title: "Title2", value1: "value1", value2: "value2"},
      {title: "Title1", value1: "value1", value2: "value2"},
      {title: "Title3", value1: "value1", value2: "value2"},
      {title: "Title2", value1: "value1", value2: "value2"},
      {title: "Title1", value1: "value1", value2: "value2"},
      {title: "Title3", value1: "value1", value2: "value2"},
      {title: "Title1", value1: "value1", value2: "value2"},
    ];
    var newArray = [];

    for(var i = 0; i<originalArray.length; i++){
      var object = {};
      object.title=originalArray[i].title;
      var values = [];
      values.push({value1: originalArray[i].value1});
      values.push({value2: originalArray[i].value2});
      object.values= values;
      newArray.push(object);
    }

This will work, although honestly, I don't know why you have some duplicated tittles. I supossed that it was just an example. If not, the answer is another.

Upvotes: 1

Related Questions