Deep Kakkar
Deep Kakkar

Reputation: 6305

count by value in array of objects in javascript using lodash

I have an array of objects as follows:

var input_array = [{
    role_name: 'Full Stack Developer',
    position_id: 'b0f00e68-5adc-4209-aec2-9c4962550ab1',
    email_address: '[email protected]',
    application_id: '1dd45634-c283-4a96-a28a-d8a63c418329',
    state: 'qualified',
    closing_date: '2018-10-28 06:30:00' },
{
    role_name: 'Delivery Representative',
    position_id: '090276f0-3fca-4b2a-85ed-697d21c405a0',
    email_address: '[email protected]',
    application_id: 'aa7fe2dd-b141-4c64-8350-a1d57bfaa502',
    state: 'interview',
    closing_date: '2018-10-28 06:30:00' },
{
    role_name: 'Delivery Representative',
    position_id: '12345678-5adc-4209-aec2-9c4962550ab1',
    email_address: '[email protected]',
    application_id: '166da0ac-aaf1-400d-9a62-e37962f66653',
    state: 'interview',
    closing_date: '2018-10-28 06:30:00' },
{
    role_name: 'Delivery Representative',
    position_id: '090276f0-3fca-4b2a-85ed-697d21c405a0',
    email_address: '[email protected]',
    application_id: 'da09a617-8e82-43c0-b1ea-725110a2c4cb',
    state: 'interview',
    closing_date: '2018-10-28 06:30:00' },
{
    role_name: 'Delivery Representative',
    position_id: '12345678-5adc-4209-aec2-9c4962550ab1',
    email_address: '[email protected]',
    application_id: '1d55a51a-ecd1-43ea-9cf4-fed101dbebda',
    state: 'offer',
    closing_date: '2018-10-28 06:30:00' },
{
    role_name: 'Micro Space Planner',
    position_id: 'fe30930f-7d9f-4953-8939-6d9924462b2b',
    email_address: '[email protected]',
    application_id: '293bd084-64f0-4c83-9b5d-aa304e44f066',
    state: 'screening',
    closing_date: '2018-10-28 06:30:00' },
{
    role_name: 'Delivery Representative',
    position_id: '12345678-5adc-4209-aec2-9c4962550ab1',
    email_address: '[email protected]',
    application_id: '2adc5236-989d-49f2-ab3e-cb7e42798b77',
    state: 'qualified',
    closing_date: '2018-10-28 06:30:00' },
{
    role_name: 'Micro Space Planner',
    position_id: 'fe30930f-7d9f-4953-8939-6d9924462b2b',
    email_address: '[email protected]',
    application_id: '293bd084-64f0-4c83-9b5d-aa304e44f066',
    state: 'screening',
    closing_date: '2018-10-28 06:30:00' },
{
    role_name: 'Delivery Representative',
    position_id: '12345678-5adc-4209-aec2-9c4962550ab1',
    email_address: '[email protected]',
    application_id: '2adc5236-989d-49f2-ab3e-cb7e42798b77',
    state: 'qualified',
    closing_date: '2018-10-28 06:30:00' }]

I want to count the object with the state as offer and interview corresponding to each and every position. I am using npm lodash library.

I have checked a few questions on SO about the group by and count using the filter but in my case position id is dynamic. So I can not set the specific value of position_id using which I can group the objects.

e.g. position_id as '12345678-5adc-4209-aec2-8b3962550ce7' contains 1 offer and 1 interview

Expected Output:

{
    role_name: 'Delivery Representative',
    position_id: '12345678-5adc-4209-aec2-9c4962550ab1',
    email_address: '[email protected]',
    offer_count: 1,
    interview_count: 1
},
{
    role_name: 'Micro Space Planner',
    position_id: 'fe30930f-7d9f-4953-8939-6d9924462b2b',
    email_address: '[email protected]',
    offer_count: 0,
    interview_count:0
},
{
    role_name: 'Delivery Representative',
    position_id: '090276f0-3fca-4b2a-85ed-697d21c405a0',
    email_address: '[email protected]',
    offer_count: 0,
    interview_count:2
}

Upvotes: 0

Views: 857

Answers (4)

Akrion
Akrion

Reputation: 18525

You can do this with something like this without lodash and via reduce, Object.assign & Object.values:

var data = [{ role_name: 'Full Stack Developer', position_id: 'b0f00e68-5adc-4209-aec2-9c4962550ab1', email_address: '[email protected]', application_id: '1dd45634-c283-4a96-a28a-d8a63c418329', state: 'qualified', closing_date: '2018-10-28 06:30:00' }, { role_name: 'Delivery Representative', position_id: '090276f0-3fca-4b2a-85ed-697d21c405a0', email_address: '[email protected]', application_id: 'aa7fe2dd-b141-4c64-8350-a1d57bfaa502', state: 'interview', closing_date: '2018-10-28 06:30:00' }, { role_name: 'Delivery Representative', position_id: '12345678-5adc-4209-aec2-9c4962550ab1', email_address: '[email protected]', application_id: '166da0ac-aaf1-400d-9a62-e37962f66653', state: 'interview', closing_date: '2018-10-28 06:30:00' }, { role_name: 'Delivery Representative', position_id: '090276f0-3fca-4b2a-85ed-697d21c405a0', email_address: '[email protected]', application_id: 'da09a617-8e82-43c0-b1ea-725110a2c4cb', state: 'interview', closing_date: '2018-10-28 06:30:00' }, { role_name: 'Delivery Representative', position_id: '12345678-5adc-4209-aec2-9c4962550ab1', email_address: '[email protected]', application_id: '1d55a51a-ecd1-43ea-9cf4-fed101dbebda', state: 'offer', closing_date: '2018-10-28 06:30:00' }, { role_name: 'Micro Space Planner', position_id: 'fe30930f-7d9f-4953-8939-6d9924462b2b', email_address: '[email protected]', application_id: '293bd084-64f0-4c83-9b5d-aa304e44f066', state: 'screening', closing_date: '2018-10-28 06:30:00' }, { role_name: 'Delivery Representative', position_id: '12345678-5adc-4209-aec2-9c4962550ab1', email_address: '[email protected]', application_id: '2adc5236-989d-49f2-ab3e-cb7e42798b77', state: 'qualified', closing_date: '2018-10-28 06:30:00' }, { role_name: 'Micro Space Planner', position_id: 'fe30930f-7d9f-4953-8939-6d9924462b2b', email_address: '[email protected]', application_id: '293bd084-64f0-4c83-9b5d-aa304e44f066', state: 'screening', closing_date: '2018-10-28 06:30:00' }, { role_name: 'Delivery Representative', position_id: '12345678-5adc-4209-aec2-9c4962550ab1', email_address: '[email protected]', application_id: '2adc5236-989d-49f2-ab3e-cb7e42798b77', state: 'qualified', closing_date: '2018-10-28 06:30:00' }]

const combine = (r = {offer_count: 0, interview_count: 0}, c) => {
   r.offer_count += c.state ==='offer'
   r.interview_count += c.state === 'interview'
   let {application_id, state, closing_date, ...rest} = c
   return Object.assign(r, rest)
}
const countEm = d => Object.values(d.reduce((r,c) => (r[c.position_id] = combine(r[c.position_id], c), r), {}))

console.log(countEm(data))

Upvotes: 0

Ele
Ele

Reputation: 33736

You can use the function reduce to group the objects by id and the function Object.values to extract the grouped objects.

let input_array = [{    role_name: 'Full Stack Developer',    position_id: 'b0f00e68-5adc-4209-aec2-9c4962550ab1',    email_address: '[email protected]',    application_id: '1dd45634-c283-4a96-a28a-d8a63c418329',    state: 'qualified',    closing_date: '2018-10-28 06:30:00' },{    role_name: 'Delivery Representative',    position_id: '090276f0-3fca-4b2a-85ed-697d21c405a0',    email_address: '[email protected]',    application_id: 'aa7fe2dd-b141-4c64-8350-a1d57bfaa502',    state: 'interview',    closing_date: '2018-10-28 06:30:00' },{    role_name: 'Delivery Representative',    position_id: '12345678-5adc-4209-aec2-9c4962550ab1',    email_address: '[email protected]',    application_id: '166da0ac-aaf1-400d-9a62-e37962f66653',    state: 'interview',    closing_date: '2018-10-28 06:30:00' },{    role_name: 'Delivery Representative',    position_id: '090276f0-3fca-4b2a-85ed-697d21c405a0',    email_address: '[email protected]',    application_id: 'da09a617-8e82-43c0-b1ea-725110a2c4cb',    state: 'interview',    closing_date: '2018-10-28 06:30:00' },{    role_name: 'Delivery Representative',    position_id: '12345678-5adc-4209-aec2-9c4962550ab1',    email_address: '[email protected]',    application_id: '1d55a51a-ecd1-43ea-9cf4-fed101dbebda',    state: 'offer',    closing_date: '2018-10-28 06:30:00' },{    role_name: 'Micro Space Planner',    position_id: 'fe30930f-7d9f-4953-8939-6d9924462b2b',    email_address: '[email protected]',    application_id: '293bd084-64f0-4c83-9b5d-aa304e44f066',    state: 'screening',    closing_date: '2018-10-28 06:30:00' },{    role_name: 'Delivery Representative',    position_id: '12345678-5adc-4209-aec2-9c4962550ab1',    email_address: '[email protected]',    application_id: '2adc5236-989d-49f2-ab3e-cb7e42798b77',    state: 'qualified',    closing_date: '2018-10-28 06:30:00' },{    role_name: 'Micro Space Planner',    position_id: 'fe30930f-7d9f-4953-8939-6d9924462b2b',    email_address: '[email protected]',    application_id: '293bd084-64f0-4c83-9b5d-aa304e44f066',    state: 'screening',    closing_date: '2018-10-28 06:30:00' },{    role_name: 'Delivery Representative',    position_id: '12345678-5adc-4209-aec2-9c4962550ab1',    email_address: '[email protected]',    application_id: '2adc5236-989d-49f2-ab3e-cb7e42798b77',    state: 'qualified',    closing_date: '2018-10-28 06:30:00' }],
    result = Object.values(input_array.reduce((a, {state, role_name, position_id, email_address}) => { 
      a[position_id] = (a[position_id] || {role_name, position_id, email_address, offer_count: 0, interview_count: 0});
      a[position_id].offer_count += (state === 'offer');
      a[position_id].interview_count += (state === 'interview');
      return a;
    }, Object.create(null)));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Jared Smith
Jared Smith

Reputation: 22040

You can use a combination of reduce and map, either the native JS or lodash versions. First, reduce bins up the records by position id, then you map over the object entries to produce the array you want.

Object.entries(input_arr.reduce((acc, item) => {
  if (!acc[item.position_id]) {
    acc[item.position_id] = {
      interview_count: 0,
      offer_count: 0,
      email_address: item.email_address,
      role_name: item.role_name
    };
  }

  if (item.state === 'interview') acc[item.position_id].interview_count += 1;
  if (item.state === 'offer') acc[item.position_id].offer_count += 1;
  return acc;
}, {})).map(([position_id, {email_address, interview_count, offer_count, role_name}]) => {
  return {
    position_id,
    email_address,
    interview_count,
    offer_count,
    role_name
  };
});

Here's a fiddle

Upvotes: 1

Rodik
Rodik

Reputation: 4092

You can reduce the original array into a new hash object to hold a map of the positions and count the states of the input array.

let interviews = input_array.reduce(function(acc, cur) {  // go over every applicant
    if (!acc[cur.position_id]) {
        acc[cur.position_id] = {      //set initial object if the job is new
            role_name: cur.role_name,
            ...,
            offer_count: 0,
            interview_count:0
        }
    }

    if (cur.state === "offer") {
        acc[cur.position_id].offer_count++;
    } else if (cur.state === "interview") {
        acc[cur.position_id].interview_count++;
    }

    return acc;
}, {});

Reduce is a native JS array method, so you actually don't need to use lodash or any external libraries for this computation

Upvotes: 1

Related Questions