pbialy
pbialy

Reputation: 1083

Is reduce faster than filter + map in general?

Inspired by this question:

replace filter and map with reduce es6

I decided to test if reduce is faster than filter plus map on given example.

I made a fiddle:

var data = Array(10 ** 4).fill(null).map((_, i) => {
  return {
    checked: Math.random() < 0.5,
    val: Math.floor(Math.random() * 10000)
  }
})

f1 = () => {
  t0 = performance.now();
  data.filter(el => el.checked).map(el => el.val)
  t1 = performance.now();
  // console.log("filter plus map took " + (t1 - t0) + " milliseconds.")
  document.getElementById('filterPlusMap').innerText = t1 - t0;
}

f2 = () => {
  t0 = performance.now();
  data.reduce((prev, curr) => {
    return curr.checked ? [...prev, curr.val] : prev 
  }, [])
  t1 = performance.now();
  // console.log("reduce took " + (t1 - t0) + " milliseconds.")
  document.getElementById('reduce').innerText = t1 - t0;
}

f1();
f2();
<div>Filter plus map: <span id='filterPlusMap'></span> milliseconds</div>
<div>Reduce: <span id='reduce'></span> milliseconds</div>

and it turned out that reduce is like 100 times worse...

But then I changed assignment method in reduce and it turned out to be better than filter+map in next fiddle (like 4 times better):

var data = Array(10 ** 6).fill(null).map((_, i) => {
  return {
    checked: Math.random() < 0.5,
    val: Math.floor(Math.random() * 10000)
  }
})

f1 = () => {
  t0 = performance.now();
  data.filter(el => el.checked).map(el => el.val)
  t1 = performance.now();
  // console.log("filter plus map took " + (t1 - t0) + " milliseconds.")
  document.getElementById('filterPlusMap').innerText = t1 - t0;
}

f2 = () => {
  t0 = performance.now();
  data.reduce((prev, curr) => {
    return curr.checked ? (prev.push(curr.val), prev) : prev 
  }, [])
  t1 = performance.now();
  // console.log("reduce took " + (t1 - t0) + " milliseconds.")
  document.getElementById('reduce').innerText = t1 - t0;
}

f1();
f2();
<div>Filter plus map: <span id='filterPlusMap'></span> milliseconds</div>
<div>Reduce: <span id='reduce'></span> milliseconds</div>

Can someone pls:

  1. Explain why it changed so much between the fiddles? I.e. - why (prev.push(curr.val), prev) is so much better? And should it be used?
  2. Tell if reduce should be always prefered over filter+map ?

Upvotes: 6

Views: 5070

Answers (1)

trincot
trincot

Reputation: 351328

Explain why it changed so much between the fiddles? I.e. - why (prev.push(curr.val), prev) is so much better? And should it be used?

(arr.push(val), arr) is much faster than [...arr, val] as the latter copies the whole arr array into a new array, giving the reduce operation a O(n²) time complexity. The first only has to add 1 element to the existing arr, ... this gives a O(n) time complexity to the whole reduce operation.

Tell if reduce should be always preferred over filter+map ?

No, this really depends on the logic to be applied and what requirements you have in terms of performance. And readability also counts: filter and map tend to be a bit more readable (understandable) than reduce.

Upvotes: 13

Related Questions