Often I study some JavaScript
interview questions, suddenly I saw a question about usage of reduce
function for sorting an Array
, I r
reduce
constraints yourself to online sorting algorithms, where each element in the array is seen once and you do not now in advance the length of your array (note that using closures you could give more information to the reducing function but this kinds of defeats the purpose of the question).
insertion sort is an obvious and easy example; I won't detail the implementation as the other answers are already very good in this regard. However you can mention a few optimizations that might probably seen as very positive to the interviewer:
Use binary search to find the insertion point can reduce the complexity of an insertion step from O(n) to O(log n). This is called binary insertion sort: the overall number of comparisons will go from O(n^2) to O(n log n). This won't be faster because the real cost is due to "splicing" the output array but if you had expensive comparisons (say, sorting long strings for instance) it could make a difference.
If you sort integer, you can use radix sort and implement a linear online sorting algorithm with reduce. This is quite trickier to implement, but very suited to a reduction.
It makes no sense to use reduce here, however you could use a new array as an accumulator and do insertion sort with all elements:
array.reduce((sorted, el) => {
let index = 0;
while(index < sorted.length && el < sorted[index]) index++;
sorted.splice(index, 0, el);
return sorted;
}, []);
Here is the version without reduce:
array.sort((a, b) => a - b);
Now some general tips for writing reducers:
how must be the reduce call back function?
You either take an approach with an accumulator, then the reducer should apply a modification to the accumulator based on the current element and return it:
(acc, el) => acc
Or if accumulator and the elements have the sane type and are logically equal, you dont need to distinguish them:
(a, b) => a + b
what is the initialValue of reduce function?
You should ask yourself "What should reduce return when it is applied on an empty array?"
Now the most important: When to use reduce? (IMO)
If you want to boil down the values of an array into one single value or object.
You can use an insertion sort:
let array = [91, 4, 6, 24, 8, 7, 59, 3, 13, 0, 11, 98, 54, 23, 52, 87, 4];
let countIfLess = (array,v)=> array.reduce((c,n)=>n<v?c+1:c,0);
let countIfEqual = (array,v)=> array.reduce((c,n)=>n==v?c+1:c,0);
console.log(
array.reduce(
(a,v,i,array)=>( a[countIfLess(array,v) + countIfEqual(a,v)]=v, a ),
new Array(array.length)
)
);
This will create the destination array once and then perform insertions into it at each step of the reduce without having to recreate the destination array.
There are more efficient ways of implementing countIfEqual
but I chose to implement all the functions using reduce
rather than other array functions.