1

I have a csv file converted to a jQuery object using jQuery CSV (https://github.com/evanplaice/jquery-csv).

Here is the code for that:

    $.ajax({
        type: "GET",
        url: "/path/myfile.csv",
        dataType: "text",
        success: function(data) {
        // once loaded, parse the file and split out into data objects
        // we are using jQuery CSV to do this (https://code.google.com/p/jquery-csv/)

        var data = $.csv.toObjects(data);
    });

I'm adding up the bushels_per_day values by company and want to refactor my code to make it more compact.

Using this answer: Sum values in jQuery object by key, I am able to loop through using $.each();

The object format is like so:

    var data = [
        "0":{
            bushels_per_day: "145",
            plant_city: "Decatur",
            plant_company: "AGP",
        },
        "1":{
            bushels_per_day: "125",
            plant_city: "Cedar Rapids",
            plant_company: "AGP",
        },
        "2":{
            bushels_per_day: "345",
            plant_city: "Ralston",
            plant_company: "AGP",
        },
        "3":{
            bushels_per_day: "55",
            plant_city: "Dawson",
            plant_company: "ADM",
        },
        "4":{
            bushels_per_day: "55",
            plant_city: "Dawson",
            plant_company: "ADM",
        },
        // ... more objects
    ]

And here is the $.each() loop:

    var sumADM = 0;
    var sumAGP = 0;
    // var for each company



    $.each(data, function (index, value) {
        var capacity = parseInt(value.bushels_per_day, 10);
        var company = value.plant_company.replace(/\W+/g, '_').toLowerCase();


        if (company == 'adm') {
            sumADM += capacity;
        }
        if (company == 'agp') {
            sumAGP += capacity;
        }
        // ... and so on for each company
    });

    console.log(sumADM, sumAGP); // and so on.

This works, but how can I refactor this so that I don't need a sum variable and if statement for each company? Currently the sum variable and console.log() must be outside the loop in order to return the correct totals.

Is there a better, more compact way to do this?

Evan Plaice
  • 13,944
  • 6
  • 76
  • 94
joshuaiz
  • 415
  • 4
  • 13

1 Answers1

3

You could put the sums on an object as properties:

var sums = {
    ADM: 0,
    AGP: 0
};

$.each(data, function (index, value) {
    var capacity = parseInt(value.bushels_per_day, 10);
    var company = value.plant_company.replace(/\W+/g, '_').toUpperCase(); // Note change here

    sums[company] += capacity;
});

console.log(sums.ADM, sums.AGP); // and so on.

Or to output them in a loop:

Object.keys(sums).forEach(function(company) {
    console.log(sums[company]);
});

You could even do lazy-init, if the companies vary:

var sums = {};

$.each(data, function (index, value) {
    var capacity = parseInt(value.bushels_per_day, 10);
    var company = value.plant_company.replace(/\W+/g, '_').toUpperCase();

    sums[company] = (sums[company] || 0) + capacity;
});

Object.keys(sums).forEach(function(company) {
    console.log(sums[company]);
});

The way the sums[company] = (sums[company] || 0) + capacity; line works is that if we haven't seen that company before, sums[company] will be undefined. Since undefined is falsey, JavaScript's curiously-powerful || operator will take the right-hand operand value (0) as its result. This is also true if we have seen company before and sums[company] is 0, but that's okay, a 0 is a 0. All other values (1 and such) are truthy, so sum[company] || 0 will be 1 and such (the value of the left-hand operand).


Side note: Note I'm using toUpperCase rather than toLowerCase on the company strings, so they match the properties.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Yep sorry I used array notation for the object. @T.J this is perfect. Thanks. – joshuaiz Jan 29 '15 at 14:21
  • I'm using `toLowerCase()` because I want to append each value to a div with an id of each company. So while this is outputting the data correctly, this is not working: `$('#' + sums[company]).append('Capacity: ' + sums[company] + 'K bushels per day');`. How can I do this? – joshuaiz Jan 29 '15 at 14:45
  • @joshuaiz: Well, your ID isn't the *sum* anyway, is it? I'm thinking: `$('#' + company.toLowerCase()).append('Capacity: ' + sums[company] + 'K bushels per day');` or of course, just use lower case throughout instead of upper case and do `$('#' + company).append('Capacity: ' + sums[company] + 'K bushels per day');` – T.J. Crowder Jan 29 '15 at 14:56
  • Yep that was a stupid mistake - not enough coffee :) But the issue is that if I use that within the loop, it returns all the iterations per company, not the total. If I use that outside of the loop, I get 'company is not defined' error. – joshuaiz Jan 29 '15 at 15:42
  • @joshuaiz: Look at the code I showed after "Or to output them in a loop". You'd do that *after* the `$.each` loop. – T.J. Crowder Jan 29 '15 at 15:54
  • Strange...the `console.log(sums[company]);` outputs correctly in the forEach loop (after `$.each()`) but when I add the append statement I'm getting 'undefined' for the `sums[company]`. – joshuaiz Jan 29 '15 at 19:35