HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Reducing a large array of objects to a simple object with 8 properties

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
simpleobjectsarraywithpropertiesreducinglargeobject

Problem

I'm reducing a large array of objects to a simple object with 8 properties. I'm currently using Array.prototype.reduce to loop through the array of objects to create a new object. In order to assign a correct key to the value in the array I'm using a switch statement. My code currently works, but I'm looking to refine it. I have no control over the API and how it returns its response.

The array of objects that are returned look like this:

[
  {
    field_id:89107336,
    values : [{ value:"Star Warz"}]
  },
  {
    field_id:89107337,
    values : [{ date:"December 24, 2015"}]
  },
  {
    field_id:89107415,
    values : [
               {
                 value: { item_id:1234123}
               },
               {
                 value: { item_id:4746576}
               }
  },
  {
    field_id:89107340,
    values : [{ value:"5.00"}]
  },
  {
    field_id:89107344,
    values : [{ value:"This is description"}]
  },
  {
    field_id:89107348,
    values : [
               { 
                 value:{file_id:234234}
               }
             ]
  }
]


The object values come back random at times, so the only way for me to tell the difference between the title, the date, description, etc. Is for me to run the response through a switch statement based upon field_id. So I created an object like so:

var eventFieldIds = {
        title: 89107336,
        date: 89107337,
        attendees: 89107415,
        price: 89107340,
        desc: 89107344,
        img: 89107348
    };


Then I use a switch statement to reduce the array objects like this:

```
var newEvent = arrayObjects.reduce(function(p, c) {
switch (c.field_id) {
case eventFieldIds.title:
{
p.name = c.values[0].value;
break;
}
case eventFieldIds.date:
{
p.date = new Date(c.values[0].start_date);
break;
}
case eventFieldIds.attendees:
{

Solution

I'd flip the field-id-to-name lookup around, and give it some more detail; e.g.

function defaultConverter(values) {
  return values[0].value;
} 

var mappings = {
  "89107336": { name: "title", converter: defaultConverter },
  "89107340": { name: "price", converter: defaultConverter },
  "89107344": { name: "desc", converter: defaultConverter },
  "89107337": {
    name: "date",
    converter: function (values) {
      return new Date(values[0].start_date);
    }
  },
  "89107348": {
    name: "img",
    converter: function (values) {
      return values[0].value.file_id;
    }
  },
  "89107415": {
    name: "attendees",
    converter: function (values) {
      var items = values.map(function (v) { return v.value.item_id });
      return JSON.stringify(items);
    }
  }
};


This way you declare how each piece of data should be treated, and you can easily extend it.

Your reduce can then become this:

var output = data.reduce(function (output, obj) {
  var mapper = mappings[obj.field_id];
  if(map) {
    output[map.name] = map.converter(obj.values)
  }
  return output;
}, {});


You can make the mapping declaration a little less repetitive like so:

function Mapping(name, converter) {
  this.name = name;
  this.converter = converter || function (values) { return values[0].value };
}

var mappings = {
  "89107336": new Mapping("title"),
  "89107340": new Mapping("price"),
  "89107344": new Mapping("desc"),
  "89107337": new Mapping("date", function (values) {
    return new Date(values[0].start_date);
  }),
  "89107348": new Mapping("img", function (values) {
    return values[0].value.file_id;
  }),
  "89107415": new Mapping("attendees", function (values) {
    var items = values.map(function (v) { return v.value.item_id });
    return JSON.stringify(items);
  })
};


and still use the same reduce function.

Code Snippets

function defaultConverter(values) {
  return values[0].value;
} 

var mappings = {
  "89107336": { name: "title", converter: defaultConverter },
  "89107340": { name: "price", converter: defaultConverter },
  "89107344": { name: "desc", converter: defaultConverter },
  "89107337": {
    name: "date",
    converter: function (values) {
      return new Date(values[0].start_date);
    }
  },
  "89107348": {
    name: "img",
    converter: function (values) {
      return values[0].value.file_id;
    }
  },
  "89107415": {
    name: "attendees",
    converter: function (values) {
      var items = values.map(function (v) { return v.value.item_id });
      return JSON.stringify(items);
    }
  }
};
var output = data.reduce(function (output, obj) {
  var mapper = mappings[obj.field_id];
  if(map) {
    output[map.name] = map.converter(obj.values)
  }
  return output;
}, {});
function Mapping(name, converter) {
  this.name = name;
  this.converter = converter || function (values) { return values[0].value };
}

var mappings = {
  "89107336": new Mapping("title"),
  "89107340": new Mapping("price"),
  "89107344": new Mapping("desc"),
  "89107337": new Mapping("date", function (values) {
    return new Date(values[0].start_date);
  }),
  "89107348": new Mapping("img", function (values) {
    return values[0].value.file_id;
  }),
  "89107415": new Mapping("attendees", function (values) {
    var items = values.map(function (v) { return v.value.item_id });
    return JSON.stringify(items);
  })
};

Context

StackExchange Code Review Q#114672, answer score: 5

Revisions (0)

No revisions yet.