Reputation: 4130
I have the following array:
[
{genderAge: "Male 25-39", count: 13029, weightedCount: 18475.6824262314, matchingSegment: 2},
{genderAge: "Female 55+", count: 35639, weightedCount: 32294.5926147014, matchingSegment: 8},
{genderAge: "Female 25-39", count: 23285, weightedCount: 20645.0599977815, matchingSegment: 6},
{genderAge: "Female 18-24", count: 7745, weightedCount: 8497.30029399032, matchingSegment: 5},
{genderAge: "Male 55+", count: 38018, weightedCount: 28589.2793936886, matchingSegment: 4},
{genderAge: "Male 18-24", count: 4038, weightedCount: 8122.65161312996, matchingSegment: 1},
{genderAge: "Female 40-54", count: 23051, weightedCount: 22834.3167597392, matchingSegment: 7},
{genderAge: "Male 40-54", count: 17278, weightedCount: 19681.8852663563, matchingSegment: 3}
]
I want to transform this array of objects into an array with two objects containing the summed up data (count, weightedCount and matchingSegment) for Males and Females. Is there a shorthand way of achieving this using Lodash and/or ES6?
update: Apologies I provided the wrong data.
Upvotes: 2
Views: 1155
Reputation: 18515
Here is another simple lodash approach which uses _.groupBy and does only one loop:
var data = [ {genderAge: "Male 25-39", count: 13029, weightedCount: 18475.6824262314, matchingSegment: 2}, {genderAge: "Female 55+", count: 35639, weightedCount: 32294.5926147014, matchingSegment: 8}, {genderAge: "Female 25-39", count: 23285, weightedCount: 20645.0599977815, matchingSegment: 6}, {genderAge: "Female 18-24", count: 7745, weightedCount: 8497.30029399032, matchingSegment: 5}, {genderAge: "Male 55+", count: 38018, weightedCount: 28589.2793936886, matchingSegment: 4}, {genderAge: "Male 18-24", count: 4038, weightedCount: 8122.65161312996, matchingSegment: 1}, {genderAge: "Female 40-54", count: 23051, weightedCount: 22834.3167597392, matchingSegment: 7}, {genderAge: "Male 40-54", count: 17278, weightedCount: 19681.8852663563, matchingSegment: 3} ]
const getGenderTotals = data => {
let Males = 0, Females = 0
_.groupBy(data, (r => {/^Male/.test(r.genderAge) ? Males += r.count : Females += r.count}))
return { Males, Females }
}
console.log(getGenderTotals(data))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Since we have access to the value and we are in the _.groupBy
context you can also easily return Male
or Female
inside the groupBy iteratee function to get the actual groups etc.
Upvotes: 0
Reputation: 3386
You can use reduce method
var list = [
{genderAge: "Male 25-39", count: 13029, weightedCount: 18475.6824262314, matchingSegment: 2},
{genderAge: "Female 55+", count: 35639, weightedCount: 32294.5926147014, matchingSegment: 8},
{genderAge: "Female 25-39", count: 23285, weightedCount: 20645.0599977815, matchingSegment: 6},
{genderAge: "Female 18-24", count: 7745, weightedCount: 8497.30029399032, matchingSegment: 5},
{genderAge: "Male 55+", count: 38018, weightedCount: 28589.2793936886, matchingSegment: 4},
{genderAge: "Male 18-24", count: 4038, weightedCount: 8122.65161312996, matchingSegment: 1},
{genderAge: "Female 40-54", count: 23051, weightedCount: 22834.3167597392, matchingSegment: 7},
{genderAge: "Male 40-54", count: 17278, weightedCount: 19681.8852663563, matchingSegment: 3}
]
list.reduce(function(a, b) {
if(/^Male/.test(b['genderAge'])) {
a['male']['pop'] += b['count'];
a['male']['matchingSegment'] += b['matchingSegment'];
a['male']['weightedCount'] += b['weightedCount'];
} else if(/^Female/.test(b['genderAge'])){
a['female']['pop'] += b['count'];
a['female']['matchingSegment'] += b['matchingSegment'];
a['female']['weightedCount'] += b['weightedCount'];
}
return a;
}, {'male':{'pop':0, 'matchingSegment':0, 'weightedCount':0}, 'female':{'pop':0, 'matchingSegment':0, 'weightedCount':0}});
Upvotes: 1
Reputation: 32145
You can simply initialize an array
with two objects
, the first one for Male
and the second is for Female
.
let result = [{text: "Male", total:0}, {text: "Female", total:0}];
Then populate it with relevant data with a forEach
loop over your first array
.
array.forEach(function(a){
if(a.genderAge.indexOf("Male")>-1){
result[0].total += a.count;
}else if(a.genderAge.indexOf("Female")>-1){
result[1].total += a.count;
}
});
Demo:
var array = [
{genderAge: "Male 25-39", count: 13029, weightedCount: 18475.6824262314, matchingSegment: 2},
{genderAge: "Female 55+", count: 35639, weightedCount: 32294.5926147014, matchingSegment: 8},
{genderAge: "Female 25-39", count: 23285, weightedCount: 20645.0599977815, matchingSegment: 6},
{genderAge: "Female 18-24", count: 7745, weightedCount: 8497.30029399032, matchingSegment: 5},
{genderAge: "Male 55+", count: 38018, weightedCount: 28589.2793936886, matchingSegment: 4},
{genderAge: "Male 18-24", count: 4038, weightedCount: 8122.65161312996, matchingSegment: 1},
{genderAge: "Female 40-54", count: 23051, weightedCount: 22834.3167597392, matchingSegment: 7},
{genderAge: "Male 40-54", count: 17278, weightedCount: 19681.8852663563, matchingSegment: 3}
];
let result = [{text: "Male", total:0}, {text: "Female", total:0}];
array.forEach(function(a){
if(a.genderAge.indexOf("Male")>-1){
result[0].total += a.count;
}else if(a.genderAge.indexOf("Female")>-1){
result[1].total += a.count;
}
});
console.log(result);
Upvotes: 0
Reputation: 5836
const { Sum, mreduceMap, compose, propOr, ifElse, constant } = crocks
const data = [
{text: "Male 18-24 (12886)", value: "test_1", total: 12886},
{text: "Male 25-39 (27913)", value: "test_2", total: 27913},
{text: "Male 40-54 (29793)", value: "test__3", total: 29793},
{text: "Male 55+ (54888)", value: "test__4", total: 54888},
{text: "Female 18-24 (19354)", value: "test_5", total: 19354},
{text: "Female 25-39 (43972)", value: "test_6", total: 43972},
{text: "Female 40-54 (39327)", value: "test_7", total: 39327},
{text: "Female 55+ (52263)", value: "test_8", total: 52263}
]
const startsWith = x => str =>
typeof str === 'string' &&
str.startsWith(x)
const isSex = sex =>
compose(startsWith(sex), propOr('', 'text'))
const totalFor = sex =>
ifElse(isSex(sex), propOr(0, 'total'), constant(0))
const sumSex = sex =>
mreduceMap(Sum, totalFor(sex))
const sumMales = sumSex('Male')
const sumFemales = sumSex('Female')
const males = sumMales(data)
const females = sumFemales(data)
console.log({males, females})
<script src="https://unpkg.com/[email protected]/dist/crocks.min.js"></script>
With the crocks
library, you can use a highly functional approach to solve the problem.
Upvotes: 1
Reputation: 146
ES6
.reduce((acc,e)=>{
if (/^Male/.test(e.text)){
acc[0].total+=e.total
}
if (/^Female/.test(e.text)){
acc[1].total+=e.total
}
return acc
},[{total:0},{total:0}])
Upvotes: 0
Reputation: 386520
You could group by the wanted value and get the sum of total
.
var data = array = [{ text: "Male 18-24 (12886)", value: "test_1", total: 12886 }, { text: "Male 25-39 (27913)", value: "test_2", total: 27913 }, { text: "Male 40-54 (29793)", value: "test__3", total: 29793 }, { text: "Male 55+ (54888)", value: "test__4", total: 54888 }, { text: "Female 18-24 (19354)", value: "test_5", total: 19354 }, { text: "Female 25-39 (43972)", value: "test_6", total: 43972 }, { text: "Female 40-54 (39327)", value: "test_7", total: 39327 }, { text: "Female 55+ (52263)", value: "test_8", total: 52263 }],
result = _(data)
.groupBy(o => o.text.match(/^\S+/)[0])
.map((array, group) => ({ group, sum: _.sumBy(array, 'total') }))
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Upvotes: 1
Reputation: 198294
function sumFor(pattern, data) {
return data
.filter(item => item.text.match(pattern))
.reduce((accu, item) => accu + item.total, 0);
}
sumFor(/^Male/, data); // 125480
sumFor(/^Female/, data); // 154916
Upvotes: 2