0

How can I create arrays to group members depending on their tag?

Tags can be anything, these are just examples.

Example Input

[
  { tag: 'Red', member: 'Red-Steve' },
  { tag: 'Red', member: 'Red-Adam' },
  { tag: 'Blue', member: 'Blue-John' },
  { tag: 'Blue', member: 'Blue-James' },
  { tag: 'Blue', member: 'Blue-Igor' }
]

Example Output

{
  Red: ['Red-Steve', 'Red-Adam']
  Blue: ['Blue-John', 'Blue-James', 'Blue-Igor']
}

Edit: I just made a test case on jsperf to compare the efficiency of the different answers and also the answer from the suggested duplicate question https://jsperf.com/group-objects-reduce-vs-for-loop

The answer by @Majed Badawi was the most efficient

2

4 Answers 4

1

You can use a simple set to group them by tag as follows:

let list = [
            { tag: 'Red', member: 'Red-Steve' },
            { tag: 'Red', member: 'Red-Adam' },
            { tag: 'Blue', member: 'Blue-John' },
            { tag: 'Blue', member: 'Blue-James' },
            { tag: 'Blue', member: 'Blue-Igor' }
];
let set = {};
for(let i = 0; i < list.length; i++){
     let current = list[i];
     if(!set[current.tag])
          set[current.tag] = [current.member];
     else
          set[current.tag].push(current.member);
}
console.log(set);

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

Comments

1

collect into object map using tag as key and appending to an array

d=[
  { tag: 'Red', member: 'Red-Steve' },
  { tag: 'Red', member: 'Red-Adam' },
  { tag: 'Blue', member: 'Blue-John' },
  { tag: 'Blue', member: 'Blue-James' },
  { tag: 'Blue', member: 'Blue-Igor' }
]
console.log(
d.reduce((acc,{tag,member})=>({...acc, [tag]: [...acc[tag]||[], member]}),{})
)

8 Comments

sure, it is iterating over the array of objects using reduce, using destructuring to extract tag and member property, acc is the "accumulated" value returned after every iteration, then it is merging the accumulated object map with a new property [tag] (which will be Red or Blue) and then concatenating member to the array
all of these answers are basically doing the same thing. mine may incur a performance penalty on very large operations due to creating an object on every iteration. it just happens to take a shorter "functional" approach
That's what I'm trying to decide here since I might end up working with a large number of objects, do you think a for loop would be more efficient than reduce here?
I'd go with whatever you're comfortable with. I don't think you'll actually see a noticeable difference if your data structure is like the one you gave. And, if you used reduce without using the spread syntax to merge objects (for example you could use Object.assign instead or direct assignment like the other answers), you could avoid the object initialization penalty. If you want to be sure, I'd do a jsperf benchmark with something as close as possible to your dataset to check.
I just benchmarked with 100 objects and the for loop was obviously the winner. I used jsben.ch for the record.
|
1

The following code will do what you ask. It uses the object[variableKey] syntax to get what you are looking for.

const members=[
  { tag: 'Red', member: 'Red-Steve' },
  { tag: 'Red', member: 'Red-Adam' },
  { tag: 'Blue', member: 'Blue-John' },
  { tag: 'Blue', member: 'Blue-James' },
  { tag: 'Blue', member: 'Blue-Igor' }
]

//this will be the output object
const newObj={};

for(memberObj of members){
    const newKey = memberObj.tag;

    //if the key already existed, just add the new item to the existing array
    if(newObj[newKey]){newObj[newKey].push(memberObj.member);}
    //if the key didn't exist, create an array value for it with the new object
    else{newObj[newKey]=[memberObj.member];}
}

console.log(newObj);

Comments

0

I think this will be a good way of achieving it in modern syntax. But may be there are some aggregate functions too.

var arr = [
  { tag: 'Red', member: 'Red-Steve' },
  { tag: 'Red', member: 'Red-Adam' },
  { tag: 'Blue', member: 'Blue-John' },
  { tag: 'Blue', member: 'Blue-James' },
  { tag: 'Blue', member: 'Blue-Igor' }
];

var newArr = [];
arr.forEach(o => {
  var existing = newArr[o.tag] && newArr[o.tag].length > 0 ? newArr[o.tag] : [];
  newArr[o.tag] = [...existing, ...[o.member]];
});

console.log('newArr', newArr);

In Chrome it is giving following output in the console

Chrome Console Output

We have a similar question here Most efficient method to groupby on an array of objects

3 Comments

If you see a dupe you should vote to close and reference that as a duplicate.
Hmm. Good suggestion
As I mentioned in the latest edit of my question, I added a link to a test case that tests the accepted answer of the question you linked as well as the 2 methods answered here. The answer of the question you linked was 20% slower than the accepted answer of this question.

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.