Ben Looi
Ben Looi

Reputation: 178

Remap array to object

I have an array like this:

var records = [{
  "field1": "dogs",
  "field2": "poodle"
}, {
  "field1": "dogs",
  "field2": "alsatian"
}, {
  "field1": "dogs",
  "field2": "chowchow"
}, {
  "field1": "dogs",
  "field2": "schnauzer"
}, {
  "field1": "cats",
  "field2": "siamese"
}, {
  "field1": "cats",
  "field2": "persian"
}, {
  "field1": "fish",
  "field2": "guppy"
}, {
  "field1": "fish",
  "field2": "tiger barb"
}]

I want to iterate over the array and create a new array Pets, so that I can access it like

var Pets = [{
  "type": "dogs",
  "breeds": ["poodle", "alsatian", "chowchow", "schnauzer"]
}, {
  "type": "cats",
  "breeds": ["siamese", "persian"]
}, {
  "type": "fish",
  "breeds": ["guppy", "tiger barb"]
}]

I tried to do a for loop but it doesn't work as I use i+1 in an array like so

var thispet = {};
var Pets = [];

thispet.type = records[0].field1;
Pets.push(thispet);

for (i = 1; i < records.length; i++) {
  if (Pets[i - 1].type != records[i].field1) {
    thispet.type = records[i] field1;
    Pets.push(thispet);
  }
}

But somehow the Pets[i-1].type is not recognised as object.

I wanted to first create 3 objects in array Pets based on the 3 types of pets in the records, then sort out the second order of breeds(should be easier with push into array. I have a large record, so a loop will help greatly.

Upvotes: 1

Views: 331

Answers (2)

Xotic750
Xotic750

Reputation: 23482

A possible solution in ECMA5.

var records = [{
        "field1": "dogs",
        "field2": "poodle"
    }, {
        "field1": "dogs",
        "field2": "alsatian"
    }, {
        "field1": "dogs",
        "field2": "chowchow"
    }, {
        "field1": "dogs",
        "field2": "schnauzer"
    }, {
        "field1": "cats",
        "field2": "siamese"
    }, {
        "field1": "cats",
        "field2": "persian"
    }, {
        "field1": "fish",
        "field2": "guppy"
    }, {
        "field1": "fish",
        "field2": "tiger barb"
    }],

    x = records.reduce(function (acc, record) {
        if (!acc[record.field1]) {
            acc[record.field1] = [];
        }

        if (acc[record.field1].indexOf(record.field2) === -1) {
            acc[record.field1].push(record.field2);
        }

        return acc;
    }, {}),

    y = Object.keys(x).map(function (key) {
        return {
            type: key,
            breeds: this[key]
        };
    }, x);

document.getElementById('out').textContent = JSON.stringify(y, null, 2);
<pre id="out"></pre>

Upvotes: 2

Jon
Jon

Reputation: 437386

It would be much simpler to group the pets by type first and then reformat the result into an array:

var group, pets = [], groups = {};
for (var i = 0; i < records.length; ++i) {
    group = groups[records[i].field1] || groups[records[i].field1] = [];
    group.push(records[i].field2);
}

for (var type in groups) {
    if (!groups.hasOwnProperty(type)) continue; // just to be on the safe side
    pets.push({ type: type, breeds: groups[type] });
}

The .hasOwnProperty check is standard procedure to avoid unpleasant surprises from third party code.

Upvotes: 2

Related Questions