如何实现数组函数 reduce
更多描述 满足以下两个测试用例
// => 55
reduce([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (x, y) => x + y);
// => 155
reduce([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (x, y) => x + y, 100);
// => NaN
reduce([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (x, y) => x + y, undefined);
以下有一个特殊的测试用例,可考虑,可不考虑
// 在 lodash 中为 NaN
// 在原生API 中为 15
reduce([1, 2, 3, 4, 5, , , , , , , , , , ,], (x, y) => x + y);
TC39 规范在此: https://tc39.es/ecma262/#sec-array.prototype.reduce。可参考标准,但无需按照标准实现。
Issue 欢迎在 Gtihub Issue 中回答此问题: Issue 658
Author 回答者: shfshanyue
代码见 如何实现数组函数 reduce,可调试与测试用例
const reduce = (list, fn, ...init) => {
let next = init.length ? init[0] : list[0];
for (let i = init.length ? 0 : 1; i < list.length; i++) {
next = fn(next, list[i], i);
}
return next;
};
Author 回答者: haotie1990
Array.prototype.Reduce1 = function(callback, initialValue) {
if (typeof callback !== 'function') {
throw new TypeError('callback not a function');
}
const array = this;
const len = array.length;
let accumulator = null;
let currentIndex = 0;
let currentValue = null;
if (initialValue == null) {
// 没传入初始值的时候,取数组中第一个非 empty 的值为初始值
while(currentIndex < len && !(currentIndex in array)) {
currentIndex++;
}
if (currentIndex >= len) {// 未提供initialValue且无法在数组中找到有效值,报错
throw new Error('array is empty and initialValue is null');
}
accumulator = array[currentIndex++];
} else {
accumulator = initialValue;
}
while (currentIndex < len) {
if (currentIndex in array) {
currentValue = array[currentIndex];
accumulator = callback(accumulator, currentValue, currentIndex, array);
}
currentIndex++;
}
return accumulator;
}
Author 回答者: heretic-G
Array.prototype.reduce = function reduce(fun, init) {
const length = this.length;
let result;
let start;
if (typeof fun !== "function") {
throw new TypeError("is not fun");
}
if (length === 0 && init === undefined) {
throw new TypeError("");
}
if (init !== undefined) {
result = init;
start = 0;
} else {
for (let i = 0; i < length; i++) {
if (this.hasOwnProperty(i)) {
result = this[i];
start = i + 1;
break;
}
}
if (start === undefined) {
throw new TypeError("");
}
}
for (let i = start; i < length; i++) {
if (this.hasOwnProperty(i)) {
result = fun(result, this[i], i, this);
}
}
return result;
};
Author 回答者: shfshanyue
@heretic-G 有点小问题,对于第二个测试用例
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].reduce1((x, y) => x + y, 120);
//=> 120
Author 回答者: Asarua
function reduce(arr, cb, init) {
const l = arr.length;
if (!l) {
if (init) return init;
else throw new TypeError("Error");
}
if (init) {
for (let i = 0; i < l; i++) {
init = cb(init, arr[i], i, arr);
}
return init;
} else {
let final;
for (let i = 0; i < l; i++) {
final = cb(!i ? arr[i++] : final, !i ? arr[i++] : arr[i], i, arr);
}
return final;
}
}
Author 回答者: Kiera569
Array.prototype._reduce = function(arr, fn, defaultPre) {
let sum = 0;
let pre = defaultPre ?? arr[0];
for(let i = 0; i < arr.length; i+=1) {
pre = sum;
sum = fn(pre, arr[i], i, arr);
}
return sum;
}
Author 回答者: haotie1990
满足以下两个测试用例
// => 55 reduce([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (x, y) => x + y); // => 155 reduce([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], (x, y) => x + y, 100);
@shfshanyue
数组的map
、forEach
、filter
等方法,需要考虑callback
函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用
[0, , 2 , 3]
Author 回答者: shfshanyue
@haotie1990 这块确实没想到,我写一下
我查了下 lodash.reduce
没有此测试用例,因此我把它贴在题目描述中,可实现可不实现
Author 回答者: wangjs-jacky
使用 forEach
遍历可以过滤 undefined
function reduce(arr, fn, init) {
let pre = init ? init : arr[0];
let startIndex = init ? 0 : 1;
arr.slice(startIndex).forEach((cur) => {
pre = fn(pre, cur);
});
console.log(pre);
return pre;
}
Author 回答者: caomeibuaichibaicai
@Kiera569 如果是undefined,测试用例无法通过
Author 回答者: yxw007
function reduce(handle, initial) {
let arr = this;
if (initial != null && arr.length == 0) {
return initial;
}
if (arr.length <= 0) {
throw new Error("array can't is empty");
}
function next(pre, index) {
if (index >= arr.length) {
return pre;
}
let r = handle(pre, arr[index], index, arr);
return next(r, index + 1);
}
let res;
if (initial) {
res = next(initial, 0);
} else {
res = next(arr[0], 1);
}
return res;
}
Array.prototype.reduce = reduce;
let arr = [1, 2, 3];
let res = arr.reduce((pre, cur, index, array) => {
return pre + cur;
}, 0);
console.log(res);