0
Object.entries(obj).reduce((acc, [key, value]) => {
  if (someCondition(key, value)) {
    acc[key] = value;
  }
  return acc;
}, {});


Object.entries(obj)
  .filter(([key, value]) => someCondition(key, value))
  .reduce((acc, [key, value]) => {
    acc[key] = value;
    return acc;
  }, {});

The above two blocks do the same thing: create a copy of obj with some properties removed based on someCondition.

Which way is preferred and why?

Avery235
  • 4,756
  • 12
  • 49
  • 83
  • The one that is easier to understand. Just yesterday, I’ve used a `reduce`–`if` in an answer of mine, where _two_ arrays had to be processed together, instead of just one, so the use-case was a bit more complex. – Sebastian Simon Apr 15 '18 at 13:39
  • The second creates two "copies" (`filter` + `reduce`) vs. one in the first (`reduce`). – Andreas Apr 15 '18 at 13:39
  • `filter` then `reduce` is a bit more clear but also has a cost : O(n*m) (max is O(n²)). Where `reduce` with `if` statement has a cost of O(n). – Vivick Apr 15 '18 at 13:40
  • 2
    @Vivick Nope - it's `O(n+m)` at best – Bergi Apr 15 '18 at 13:41
  • 1
    @Vivick How has `filter` then `reduce` a higher time complexity?! It’s O(n + m), if anything. – Sebastian Simon Apr 15 '18 at 13:41
  • Totally opinion based. That said, I'd personally pick the second one, since it's more separated. The filter code is separate from the aggregation code. – rtn Apr 15 '18 at 13:53
  • @Xufox it is always O(n+m) but if there was no removal then it is O(2n) – Vivick Apr 15 '18 at 14:00
  • The `reduce` in first one does twice the amount of work compare to the `reduce` in second one due to the condition checking. So wouldn't the work done between first and second be the same (both O(2n))? – Avery235 Apr 15 '18 at 18:17

2 Answers2

5

It always depends.

With the first case - reduce with condition inside - you'll loop your dataset just once.

Second case gives you two loops (second works on limited dataset) but the code is much more readable and operations are separated (filtering / modifying data).

hsz
  • 148,279
  • 62
  • 259
  • 315
  • btw first case also may run once if you use some library that supports lazy evaluation(like lazy.js or lodash) – skyboyer Apr 15 '18 at 13:41
  • First case requires 1 additional operation on each iteration (condition check) compare to second case, so wouldn't the total work done be similar? – Avery235 Apr 15 '18 at 18:14
1

I would prefer either the completely imperative approach

function filterProperties(obj, predicate) {
    const res = {};
    for (const key in obj) {
        const val = obj[key];
        if (predicate(key, var))
            res[key] = val; 
    }
    return res;
}

or the completely functional approach

function filterProperties(obj, predicate) {
    return fromEntries(Object.entries(obj).filter(entry => predicate(...entry)));
}
function fromEntries(entries) {
    const res = {};
    for (const [key, val] of entries) // using `reduce` is not much of an advantage here
        res[key] = val;
    return res;
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375