'How do I write my own `reduce` function?

I want write reduce by myself. But over the last 4 hours, I couldn't.

var a = [10, 21, 13, 56];

function add(a, b) { return a + b }
function foo(a, b) { return a.concat(b) }

Array.prototype.reduce2 = function () {
  // I do not understand how to handle the function of the inlet
  // I know that I should use arguments, but I don't know how many arguments there will be
  var result = 0;
  for(var i = 0; i < arguments.length; i++) {
    result += arguments[i];
  }
 return result;
};

console.log(a.reduce(add), a.reduce2(add))         // 100 100
console.log(a.reduce(add, 10), a.reduce2(add, 10)) // 110 110

Yes, I know that this seems like a lot of topics, but I couldn't find answer. What am I missing, or doing wrong here?



Solution 1:[1]

The array in subject is not passed as argument, but is the context (this).

You also need to distinguish between the presence or absence of the start value:

var a = [10, 21, 13, 56];

function add(a, b) { return a + b }
function foo(a, b) { return a.concat(b) }

Array.prototype.reduce2 = function (f, result) {
  var i = 0;
  if (arguments.length < 2) {
    i = 1;
    result = this[0];
  }
  for(; i < this.length; i++) {
    result = f(result, this[i], i, this);
  }
  return result;
};
console.log(a.reduce(add), a.reduce2(add))         // 100 100
console.log(a.reduce(add, 10), a.reduce2(add, 10)) // 110 110
// extra test with foo:
console.log(a.reduce(foo, 'X'), a.reduce2(foo, 'X')) // X10211356 X10211356

Solution 2:[2]

Based on your code

var a = [10, 21, 13, 56];

function add(a, b) { return a + b }
function foo(a, b) { return a.concat(b) }

Array.prototype.reduce2 = function(fn, start){
  var result = start !== undefined ? start : this[0];
  for (var i = 0; i < this.length; i++) {
    result = fn(result, this[i]);
  }
  return result;
};
console.log(a.reduce(add), a.reduce2(add))         // 100 100
console.log(a.reduce(add, 10), a.reduce2(add, 10)) // 110 110
console.log(a.reduce(foo, ''), a.reduce2(foo, ''));
console.log(a.reduce(foo, 'X'), a.reduce2(foo, 'X'));

Solution 3:[3]

I'm not sure that my answer is exactly answering the question, but I hope this may help someone.

Example without using prototype and loops:

const origArr = [2,2]
const origFunc = (p,c) => p+c
const initial = 1

const reduce = (func, array, initial) => {
  const rec = (arr, acc) => {
    // arr: [2, 2], [2], []
    // acc: 1, 3, 5
    if (!arr.length) return acc
    const curr = arr[0]
    const nextArr = arr.slice(1)
    const nextAcc = func(acc, curr)
    return rec(nextArr, nextAcc)
  }
  if (initial) {
    return rec(array, initial)
  }
  return rec(array.slice(1), array[0])
}

console.log(origArr.reduce(origFunc, initial)) // 5
console.log(reduce(origFunc, origArr, initial)) // 5

And example with loop:

const reduceLoop = (func, array, initial) => {
    let acc = initial !== undefined ? initial : array[0]
    let arr = initial !== undefined ? [initial, ...array] : array
    for(let i=1;i<arr.length;i++) {
      acc = func(acc, arr[i])
    }
    return acc
}

As you you can see, in first example we do not assigning variables, we just have some constants, but in the example with loop we assigning tha acc variable.

Solution 4:[4]

Below code reduces the passed array to single value. Need to pass a function on what has to be done on the array and initial value if needed.

Array.prototype.myFunction = function(fn,initial) {
    let arayEl = this;
    console.log(arayEl);
    let total = initial || 0;
    for(let i=0;i<arayEl.length;i++) {
        total = fn(total,arayEl[i]);
    }
    return total;
}

console.log([1,2,3].myFunction(function(total,x){return total +x},10));
console.log([1,2,3].reduce(function(total,x){return total +x},10));
console.log([1,2,3].myFunction(function(total,x){return total * x},10));
console.log([1,2,3].reduce(function(total,x){return total * x},10));
  • myFunction is custom reduce function which accepts a callback funtion(fn) and a initial value which is optional. It will work just like reducer.
  • callBack function function(total,x){return total + x} is passed as param to myFunction which is then reduced to single value. Here instead of add, we can perform any operation same like reduce.

Solution 5:[5]

const reduceV1 = (list, cb, intial) => {
  let memo = intial;
  for (let i = 0; i < list.length; i++) {
    if (i === 0 && memo === undefined) {
      memo = list[0];
    } else {
      memo = cb(list[i], memo);
    }
  }

  return memo;
};

function sumV1(n, sum) {
  return n + sum;
}

console.log(reduceV1([1, 2], sumV1));
console.log(reduceV1([1, 2,3], sumV1,0));

Solution 6:[6]

Actual reduce fuction:

const list = [1,2,3,4,5];
const sum = list => list.reduce((total, val)=> total+val, 0)
console.log(sum(list));

If we look closely then we need three things: a list to iterate over , initial value and a reduce function

const reduceHelper = (list, initialValue, reducer) => {
// If the list is empty we will just return initial value
  if(list.length === 0) {
    return initialValue;
  } else {
    const [first, ...rest] = list;
    const updatedAcc = reducer(initialValue, first);
    return reduceHelper(rest, updatedAcc, reducer);
  }
}
// test it 
const list = [1,2,3,4,5];
console.log( myReduce(list, 0, (total, val) => total + val))

The idea is the same. We can follow the same idea and write different reduce function for counting words.......

Solution 7:[7]

Array.prototype.myReduce = function(callback, initialValue) {
  var a = initialValue;
  for(let i=0; i<this.length;i++){
     callback(a=a+this[i]);
  }
  return a;
}
var arr = [1,2,3,4,5];
var result = arr.myReduce((next,prev) =>next+prev,10);
console.log(result);                    //25

Solution 8:[8]

With ES6 Default Parameters:

const nums = [1, 5, 5, 9];

Array.prototype.customReduce = function (callback, initial=0) {
  let result = initial;
  for (let i = 0; i < this.length; i++) {
    result = callback(result, this[i]);
  }
  return result;
};

const sum = nums.customReduce((acc, value) => acc + value, 0);
console.log(sum); // 20

Solution 9:[9]

Array.prototype.customReduce = function (callback, initial) {
const arr = this
for (let i = 0; i < arr.length; i++) {
    if (initial === undefined && i === 0) {
        initial = arr[0]
        continue
    }
    initial = callback(initial, arr[i], i)
}
return initial

}

Solution 10:[10]

var a = [10, 21, 13, 56];

function add(a, b) { return a + b }

Array.prototype.reduce2 = function(fn, start){
  var result = start !== undefined ? start : this[0];
  for (var i = 1; i < this.length; i++) {
    result = fn(result, this[i]);
  }
  return result;
};
console.log(a.reduce(add), a.reduce2(add))  

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3
Solution 4
Solution 5 ASHISH R
Solution 6 ASHISH R
Solution 7 Utkarsh Joshi
Solution 8 Mr.spShuvo
Solution 9 harutyunian
Solution 10 Bhaskar Mishra