1

I have some javascript that is fetching some JSON and I'm trying to combine certain rows of information together to use in a table.

The JSON looks like below:

[{"Code":"12345","Name":"foo","Service":"Payments"},
{"Code":"12345","Name":"foo","Service":"Marketing"},
{"Code":"23456","Name":"bar","Service":"Payments"},
{"Code":"23456","Name":"bar","Service":"Development"},
{"Code":"34567","Name":"baz","Service":"Marketing"}]

Basically some rows share the exact same information with each other except for one field, Service.

My thought was to try to turn each row into an object that I can either update or merge with another object that shares the same Code.

That object and code looks something like this:

function CustObj(code,name,hasPay,hasMarket,hasDev) {
  this.code = code;
  this.name = name;
  this.hasPay = hasPay;
  this.hasMarket = hasMarket;
  this.hasDev = hasDev;
}

function formatData(data) {
  var formatedData = [];
  for (var key in data) {
    var customer = new CustObj(data[key].Code,data[key].Name);
    switch (data[key].Service) {
      case 'Payments':
        customer.hasPay = true;
        break;
      case 'Marketing':
        customer.hasMarket = true;
        break;
      case 'Development':
        customer.hasDev = true;
        break;
    }
    formatedData.push(school);
  }
}

The problem is that I want to have one object for each unique Code but that has the correct amount of flags based on Service but I haven't figured out how to do that yet. I was looking at doing something like $.extend(formatedData,customer) to merge objects but I can't seem to get the right logic for locating the two objects that I'm trying to merge.

Any thoughts on how this can be accomplished?

2
  • Would using the Underscore.js library be allowable? It has some methods in there that might potentially be useful for this, like groupBy. Commented May 23, 2014 at 19:07
  • I haven't used it before but I should be able to. Commented May 23, 2014 at 19:08

2 Answers 2

2

You can process the array for duplicates and create a new array where the "Service" property is an array of services that share the same Code and Name:

var data = [
    {"Code":"12345","Name":"foo","Service":"Payments"},
    {"Code":"12345","Name":"foo","Service":"Marketing"},
    {"Code":"23456","Name":"bar","Service":"Payments"},
    {"Code":"23456","Name":"bar","Service":"Development"},
    {"Code":"34567","Name":"baz","Service":"Marketing"}
];

function mergeServices(data) {
    var result = [], item, match, found;
    // for each array item
    for (var i = 0; i < data.length; i++) {
        item = data[i];
        found = false;
        for (var j = 0; j < result.length; j++) {
            // see if we have a dup of a previously existing item
            if (item.Code == result[j].Code && item.Name == result[j].Name) {
                // just add the Service name to the array of the previous item
                result[j].Service.push(item.Service);
                found = true;
                break;
            }
        }
        if (!found) {
            // copy the current row (so we can change it without changing original)
            var newItem = {};
            for (var prop in item) {
                newItem[prop] = item[prop];
            }
            // convert service to an array
            newItem.Service = [newItem.Service];
            result.push(newItem);
        }
    }
    return result;
}

var output = mergeServices(data);

That produces this output:

[
    {"Code":"12345","Name":"foo","Service":["Payments","Marketing"]},
    {"Code":"23456","Name":"bar","Service":["Payments","Development"]},
    {"Code":"34567","Name":"baz","Service":["Marketing"]}
]

Working jsFiddle: http://jsfiddle.net/jfriend00/6rU2z/

Sign up to request clarification or add additional context in comments.

Comments

2

As you create your customers you can add them to a map (an object) so that they can be referenced by code. You only create customers that are not already in the map. For each row you get or create the corresponding customer and set the corresponding flag.

function formatData(data) {
    var customerMap = {};
    $(data).each(function(index, elem){

        // Get the customer if it is already in the map, else create it
        var customer = customerMap[elem.Code];
        if(!customer) {
            customer = new CustObj(elem.Code, elem.Name);
            customerMap[elem.Code] = customer;
        }

        // Add flags as appropiate
        switch (elem.Service) {
            case 'Payments':
                customer.hasPay = true;
                break;
            case 'Marketing':
                customer.hasMarket = true;
                break;
            case 'Development':
                customer.hasDev = true;
                break;
        }
    });

    // Convert map to array
    var formatedData = [];
    for(var code in customerMap){
        formatedData.push(customerMap[code]);
    }
}

function CustObj(code,name) {
    this.code = code;
    this.name = name;
    this.hasPay = false;
    this.hasMarket = false;
    this.hasDev = false;
}

EDIT I've created a fiddle to demonstrate this

JSFiddle

3 Comments

Generally looks good, except one thing: this will result in hasDev, hasMarket, or hasPay to either have the value true or undefined - ideally, we want true or false.
@SergeyK then just set them to false in the constructor to begin with. I've edited my answer.
If I could select two answers as correct I would select yours too as it does exactly what I asked for. However, I think @jfriend00 answer is going to fit better into the rest of script, which is the only reason I selected his over yours. I am curious to benchmark the two and see which performs faster though. Anyway, thanks for the help!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.