2

I have an array containing several objects similar to the following:

{person: {name: "Steve", id: 1}, role: 1}
{person: {name: "Phil", id: 2}, role: 1}
{person: {name: "Steve", id: 1}, role: 3}
{person: {name: "Phil", id: 2}, role: 6}

My intention is to return an array of the same type, but I'd like to return only one object per "person" with their highest role.

I understand the following will give me a single object with the highest role.

array.reduce((prev, cur) => prev.role > cur.role ? prev : cur);

How do I return each unique person and their corresponding highest role as a new array?

Like so:

{person: {name: "Steve", id: 1}, role: 3}
{person: {name: "Phil", id: 2}, role: 6}
1
  • _.map(_.groupBy(input, 'person.id'), vs => _.maxBy(vs, 'role')) Commented Dec 24, 2018 at 15:37

3 Answers 3

4

You need to collect the objects and if you have already one with the same id check the role and take the greater one.

var data = [{ person: { name: "Steve", id: 1 }, role: 1 }, { person: { name: "Phil", id: 2 }, role: 1 }, { person: { name: "Steve", id: 1 }, role: 3 }, { person: { name: "Phil", id: 2 }, role: 6 }],
    grouped = data.reduce((r, o) => {
        var index = r.findIndex(({ person: { id } }) => id === o.person.id);
        if (index === -1) {
            r.push(o);
            return r;
        }
        if (r[index].role < o.role) {
            r[index] = o;
        }
        return r;    
    }, []);

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

Sign up to request clarification or add additional context in comments.

Comments

1

Group the items by person.id with Array.reduce(), but for each id store only the object with the highest role. Convert back to array using Object.values():

const data = [{ person: { name: "Steve", id: 1 }, role: 1 }, { person: { name: "Phil", id: 2 }, role: 1 }, { person: { name: "Steve", id: 1 }, role: 3 }, { person: { name: "Phil", id: 2 }, role: 6 }];

const result = Object.values(data.reduce((r, o) => {
  const id = o.person.id;
  
  if(!r[id] || r[id].role < o.role) r[id] = o;
  
  return r;
}, []));

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

Comments

1

You could use Array.prototype.reduce and build out an object literal like below. Use the person.name property value as the object key and then just update the role value if you find a higher value:

var people = [{
  person: {
    name: "Steve",
    id: 1
  },
  role: 1
}, {
  person: {
    name: "Phil",
    id: 2
  },
  role: 1
}, {
  person: {
    name: "Steve",
    id: 1
  },
  role: 3
}, {
  person: {
    name: "Phil",
    id: 2
  },
  role: 6
}];

var highRoleByPerson = people.reduce((accum, el) => {
  if (accum[el.person.name]) {
    if (el.role > accum[el.person.name].role) {
      accum[el.person.name].role = el.role;
    }
  } else {
    accum[el.person.name] = {
      person: {
        name: el.person.name,
        id: el.person.id
      },
      role: 0
    };
  }
  return accum;
}, {});

console.log(highRoleByPerson);

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.