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?
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.