2

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.

7 Answers 7

2
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
Sign up to request clarification or add additional context in comments.

1 Comment

I like it :) With a snippet it would be perfect <3
1

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}});

Comments

1

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>

Comments

1

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.

Comments

0

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}])

1 Comment

In general when answering you should supply some explanatory text as to the specifics of how the code works.
0

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);

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.