iamrkasula
iamrkasula

Reputation: 274

Filter an array based on object different values

I want to simplify an array of objects filtering. Let's assume that I have following array,

const users = [{
    name: "user1",
    gender: "m"
  }, {
    name: "user2",
    gender: "f"
  }, {
    name: "user3",
    gender: "f"
  }, {
    name: "user4",
    gender: "m"
  }, {
    name: "user5",
    gender: "m"
  }];

For example i need to filter all users by male or female, so i do loop through filter object property:

const fUsers = users.filter(user => user.gender === "f");
const mUsers = users.filter(user => user.gender === "m");

const results = [fUsers, mUsers];
console.log(results);

Is there any better way to filter to do it in one shot, so i can get results in mutiple arrays.

Upvotes: 2

Views: 141

Answers (5)

altruios
altruios

Reputation: 1083

this will work, instead of two filters, you can reduce into an array of two arrays, sorting as you go. the acc is set after the function that reduce uses.

const sortedByGender =users.reduce((acc, user)=>{
  user.gender==="f"?acc[0].push(user):acc[1].push(user);
  return acc;
},[[],[]]);

Upvotes: 0

l2ysho
l2ysho

Reputation: 3053

Basic approach

forEach

Basically for any kind of operation with array, you can use a forEach.In this case you just create as much help variables as you neeed and process filter logic in forEach.

const males = []
const females = []
users.forEach(u=> u.gender === 'm' ? males.push(u) : females.push(u))

Another javascript Loop

Another simple solution is to use one of javascript loops, in my example I have chosen for-in but principle is the same as in forEach example

const males = []
const females = []
for (u in users) {
    if (u.gender === 'm') {
        males.push(u)
    } else { 
        females.push(u)
    }
}

Advanced approach

reduce

Reduce is function which allows as to process array loop and store result to single variable called accumulator, which is shared in every loop step. We can use [[],[]] => array of arrays accumulator

const [males, females] = users.reduce((acc, user) => {
      if (user.gender === 'm') {
        acc[0].push(u)
      } else {
        acc[1].push(u)
      }
      return acc;
    }, [[], []])

reduce one-liner

Same principle as the last, but refactored to one line. (not the beast readability)

const [males, females] = users.reduce((acc, u) => (u.gender === 'm' ? acc[0].push(u) : acc[1].push(u), acc), [[],[]])

lodash/underscore

If you use lodash, you can use a groupBy function, which create object with keys consist of filter attributes and array values, same function you can find also in underscore.

const result = _.groupBy(users, 'gender'));
// { 'm': [{male1, male2}], 'f': [female1, female2] }

Upvotes: 2

Nina Scholz
Nina Scholz

Reputation: 386550

You could group by gender and take a destructuring with a renaming to the wanted variable names.

const
    users = [{ name: "user1", gender: "m" }, { name: "user2", gender: "f" }, { name: "user3", gender: "f" }, { name: "user4", gender: "m" }, { name: "user5", gender: "m" }],
    { f: fUsers, m: mUsers } = users.reduce((r, o) => ((r[o.gender] ??= []).push(o), r), {});

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

Upvotes: 0

Derek Wang
Derek Wang

Reputation: 10193

This can be done using Array.reduce.

On Array.reduce callback, if gender is m, you can push to acc[0] and if gender is f, you can push to acc[1].

const users = [{
  name: "user1",
  gender: "m"
}, {
  name: "user2",
  gender: "f"
}, {
  name: "user3",
  gender: "f"
}, {
  name: "user4",
  gender: "m"
}, {
  name: "user5",
  gender: "m"
}];

const result = users.reduce((acc, cur) => {
  cur.gender === 'f' ? acc[0].push(cur) : acc[1].push(cur);
  return acc;
}, [ [], [] ]);
console.log(result);

Upvotes: 3

brk
brk

Reputation: 50291

You can use reduce function and in the accumulator pass a nested array. In the callback check the gender and you can use acc[0] to add elements in the first nested array of the accumulator or acc[1]

const users = [{
  name: "user1",
  gender: "m"
}, {
  name: "user2",
  gender: "f"
}, {
  name: "user3",
  gender: "f"
}, {
  name: "user4",
  gender: "m"
}, {
  name: "user5",
  gender: "m"
}];

const newArr = users.reduce((acc, curr) => {
  if (curr.gender === 'f') {
    acc[0].push(curr)
  } else {
    acc[1].push(curr)
  }
  return acc;
}, [
  [],
  []
]);

console.log(newArr)

Alternatively you can also use normal for loop

const users = [{
  name: "user1",
  gender: "m"
}, {
  name: "user2",
  gender: "f"
}, {
  name: "user3",
  gender: "f"
}, {
  name: "user4",
  gender: "m"
}, {
  name: "user5",
  gender: "m"
}];

let arr = [
  [],
  []
];
for (let i = 0; i < users.length; i++) {
  users[i].gender === 'f' ? arr[0].push(users[i]) : arr[1].push(users[i])
};

console.log(arr)

Upvotes: 4

Related Questions