2

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.

1
  • you could use reduce to output an array with two arrays of filtered content. Commented Oct 21, 2020 at 15:53

5 Answers 5

4

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)

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

1 Comment

ternary operators are perfect for this, and reduce line count.
3

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);

Comments

2

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] }

Comments

0

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; }

Comments

0

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;
},[[],[]]);

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.