4

So the requirement is like: I got a array of objects (e.g. Array)

[
   { empDept: 'Engineering', empLoc: 'Pune', empName: 'John' },
   { empDept: 'Engineering', empLoc: 'Mumbai', empName: 'Harry' },
   { empDept: 'HR', empLoc: 'Pune', empName: 'Denis' },
   { empDept: 'Finance', empLoc: 'Mumbai', empName: 'Elvis' },
]

I will have a function which will accept the name of the property as a parameter, on which the employee list will be grouped. So if the input parameter value is 'empDept', then I want the result as below:

[
   {
      key: 'Engineering',
      values: [
         { empDept: 'Engineering', empLoc: 'Pune', empName: 'John' },
         { empDept: 'Engineering', empLoc: 'Mumbai', empName: 'Harry' },
     ]
   },
   {
      key: 'HR',
      values: [
         { empDept: 'HR', empLoc: 'Pune', empName: 'Denis' },
     ]
   },
   {
      key: 'Finance',
      values: [
        { empDept: 'Finance', empLoc: 'Mumbai', empName: 'Elvis' },
     ]
   }
]

I'm using the RxJs groupBy operator to achieve this. I have tried the below code, but it doesn't seem to give the desired result:

this.groupedEmployees$ = employees$.pipe(
      groupBy(person => person.empDept),
      mergeMap(group => of({ key: group.key, values: group.pipe(mergeMap(x => toArray())) })),
    );

Appreciate your help.

2

3 Answers 3

10

If you really want to stick with RxJS, you can use this piece of code:

import { from } from 'rxjs'; 
import { groupBy, mergeMap, reduce, toArray } from 'rxjs/operators';

const groupedEmployees$ = from([
  { empDept: 'Engineering', empLoc: 'Pune', empName: 'John' },
  { empDept: 'Engineering', empLoc: 'Mumbai', empName: 'Harry' },
  { empDept: 'HR', empLoc: 'Pune', empName: 'Denis' },
  { empDept: 'Finance', empLoc: 'Mumbai', empName: 'Elvis' }
]).pipe(
  groupBy(person => person.empDept),
  mergeMap(group => group
    .pipe(
      reduce((acc, cur) => {
          acc.values.push(cur);
          return acc;
        },
        { key: group.key, values: [] }
      )
    )
  ),
  toArray()
);

groupedEmployees$.subscribe(console.log);
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, but why does it console.log twice, separately for each key-value pairs. I fixed it by adding a toArray() operator.
I'm sorry, I didn't notice you wanted an array of these objects. Yes, adding toArray() would convert it to what you wanted. I'll edit my question.
1

Are you looking for something like this?

function groupBy(key, array) {
  return array.reduce((all, current) => {
    const existingKey = all.find(existing => existing.key === current[key]);
    if (!existingKey) {
      all.push({key: current[key], values: [current]});
    } else {
      existingKey.values.push(current);
    }
    return all;
  }, []);
}

Example:

const arr = [
   { empDept: 'Engineering', empLoc: 'Pune', empName: 'John' },
   { empDept: 'Engineering', empLoc: 'Mumbai', empName: 'Harry' },
   { empDept: 'HR', empLoc: 'Pune', empName: 'Denis' },
   { empDept: 'Finance', empLoc: 'Mumbai', empName: 'Elvis' },
];

const byDept = groupBy('empDept', arr);
const byLoc = groupBy('empLoc', arr);

Comments

0

Why would you use rxjs in this case? It's purely array transformation. You can use lodash groupBy: https://lodash.com/docs/#groupBy


const t = [
   { empDept: 'Engineering', empLoc: 'Pune', empName: 'John' },
   { empDept: 'Engineering', empLoc: 'Mumbai', empName: 'Harry' },
   { empDept: 'HR', empLoc: 'Pune', empName: 'Denis' },
   { empDept: 'Finance', empLoc: 'Mumbai', empName: 'Elvis' },
];

const result = Object.entries(_.groupBy(t, 'empDept')).map(([key, values]) => ({key, values}));

6 Comments

Thanks for you answer. But I prefer RxJs because I'm dealing with observables.
That's what we call overkill: you make it more complex than it should be. Do not forget rxjs purpose: RxJS is a library for composing asynchronous and event-based programs by using observable sequences. It provides one core type, the Observable, satellite types (Observer, Schedulers, Subjects) and operators inspired by Array#extras (map, filter, reduce, every, etc) to allow handling asynchronous events as collections. and Think of RxJS as Lodash for events.
Why would using RxJS be considered an overkill whilst using Lodash wouldn't?
You can even do it without Lodash. With lodash, you can write it in 1 line like I did, with only one method groupBy. How many lines did you write with rxjs, and with how many functions?
Yes, Lodash fixes this problem in one line, but what if OP's employees$ Observable is an asynchronous source that was already handled by RxJS so they just wanted to continue using RxJS not wanting to mix different approaches (e.g. adding Lodash solution)? I would call using two libraries as an overkill. And I'm not sure how would you solve this in one line without Lodash.
|

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.