Javascript 如何打破reduce方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36144406/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to break on reduce method
提问by Julio Marins
How can I break the iteration on reduce method?
如何打破reduce方法的迭代?
for
为了
for (var i = Things.length - 1; i >= 0; i--) {
if(Things[i] <= 0){
break;
}
};
reduce
降低
Things.reduce(function(memo, current){
if(current <= 0){
//break ???
//return; <-- this will return undefined to memo, which is not what I want
}
}, 0)
采纳答案by Tobiah Rex
UPDATE
更新
Some of the commentators make a good point that the original array is being mutated in order to break early inside the .reduce()
logic.
一些评论员提出了一个很好的观点,即原始数组正在发生变异,以便在.reduce()
逻辑内部尽早中断。
Therefore, I've modified the answer slightlyby adding a .slice(0)
before calling a follow-on .reduce()
step, yielding a copy of the original array.
NOTE: Similar ops that accomplish the same task are slice()
(less explicit), and spread operator [...array]
(slightly less performant). Bear in mind, all of these add an additional constant factor of linear time to the overall runtime + 1*(O(1)).
因此,我通过在调用后续步骤之前添加 a稍微修改了答案,从而生成原始数组的副本。
注意:完成相同任务的类似操作是(不太明确)和扩展运算符(性能稍差)。请记住,所有这些都为整体运行时间增加了一个额外的线性时间常数因子 + 1*(O(1))。.slice(0)
.reduce()
slice()
[...array]
The copy, serves to preserve the original array from the eventual mutation that causes ejection from iteration.
副本用于保护原始数组免受导致迭代弹出的最终突变。
const array = ['9', '91', '95', '96', '99'];
const x = array
.slice(0) // create copy of "array" for iterating
.reduce((acc, curr, i, arr) => {
if (i === 2) arr.splice(1); // eject early by mutating iterated copy
return (acc += curr);
}, '');
console.log("x: ", x, "\noriginal Arr: ", array);
// x: 99195
// original Arr: [ '9', '91', '95', '96', '99' ]
OLD
老的
You CAN break on any iteration of a .reduce() invocation by mutating the 4th argument of the reduce function: "array". No need for a custom reduce function. See Docsfor full list of .reduce()
parameters.
您可以通过改变 reduce 函数的第四个参数:“array”来中断 .reduce() 调用的任何迭代。不需要自定义减少功能。有关参数的完整列表,请参阅文档.reduce()
。
Array.prototype.reduce((acc, curr, i, array))
Array.prototype.reduce((acc, curr, i, array))
The 4th argument is the arraybeing iterated over.
第四个参数是被迭代的数组。
const array = ['9', '91', '95', '96', '99'];
const x = array
.reduce((acc, curr, i, arr) => {
if(i === 2) arr.splice(1); // eject early
return acc += curr;
}, '');
console.log('x: ', x); // x: 99195
WHY?:
为什么?:
The 1 and only reason I can think of to use this instead of the many other solutions presented is if you want to maintain a functional programming methodology to your algo, and you want the most declarative approach possible to accomplish that. If your entire goal is to literally REDUCE an array to an alternate non-falsey primitive (String, Number, Boolean, Symbol) then I would argue this IS in fact, the best approach.
我能想到的使用它而不是提供的许多其他解决方案的第一个也是唯一的原因是,如果您想为您的算法维护一种函数式编程方法,并且您希望使用最具声明性的方法来实现这一点。如果您的整个目标是将数组从字面上减少为替代的非假原语(字符串、数字、布尔值、符号),那么我认为这实际上是最好的方法。
WHY NOT?
为什么不?
There's a whole list of arguments to make for NOT mutating function parameters as it's a bad practice.
有一个完整的参数列表,用于不改变函数参数,因为这是一种不好的做法。
回答by RobG
You can use functions like someand everyas long as you don't care about the return value. everybreaks when the callback returns false, somewhen it returns true:
只要您不关心返回值,您就可以使用some和every 之类的函数。当回调返回 false 时每个都会中断,当它返回 true 时会中断一些:
things.every(function(v, i, o) {
// do stuff
if (timeToBreak) {
return false;
} else {
return true;
}
}, thisArg);
回答by AndroidDev
Don't use reduce. Just iterate on the array with normal iterators (for, etc) and break out when your condition is met.
不要使用减少。只需使用普通迭代器(for 等)迭代数组,并在满足条件时中断。
回答by AndroidDev
There is no way, of course, to get the built-in version of reduce
to exit prematurely.
当然,没有办法让内置版本的reduce
to 过早退出。
But you can write your own version of reduce which uses a special token to identify when the loop should be broken.
但是您可以编写自己的 reduce 版本,它使用一个特殊的标记来识别何时应该中断循环。
var EXIT_REDUCE = {};
function reduce(a, f, result) {
for (let i = 0; i < a.length; i++) {
let val = f(result, a[i], i, a);
if (val === EXIT_REDUCE) break;
result = val;
}
return result;
}
Use it like this, to sum an array but exit when you hit 99:
像这样使用它,对数组求和,但在达到 99 时退出:
reduce([1, 2, 99, 3], (a, b) => b === 99 ? EXIT_REDUCE : a + b, 0);
> 3
回答by Doug Coburn
Array.every can provide a very natural mechanism for breaking out of high order iteration.
Array.every 可以提供一种非常自然的机制来打破高阶迭代。
const product = function(array) {
let accumulator = 1;
array.every( factor => {
accumulator *= factor;
return !!factor;
});
return accumulator;
}
console.log(product([2,2,2,0,2,2]));
// 0
回答by Koudela
You can break every code - and thus every build in iterator - by throwing an exception:
您可以通过抛出异常来破坏每个代码 - 从而破坏迭代器中的每个构建:
function breakReduceException(value) {
this.value = value
}
try {
Things.reduce(function(memo, current) {
...
if (current <= 0) throw new breakReduceException(memo)
...
}, 0)
} catch (e) {
if (e instanceof breakReduceException) var memo = e.value
else throw e
}
回答by alun
Another simple implementation that I came with solving the same issue:
我解决相同问题的另一个简单实现:
function reduce(array, reducer, first) {
let result = first || array.shift()
while (array.length > 0) {
result = reducer(result, array.shift())
if (result && result.reduced) {
return result.reduced
}
}
return result
}
回答by Erik Waters
You cannot break from inside of a reduce method. Depending on what you are trying to accomplish you could alter the final result (which is one reason you may want to do this)
您不能从 reduce 方法内部中断。根据您要完成的工作,您可以更改最终结果(这是您可能想要这样做的原因之一)
[1, 1, 1].reduce((a, b) => a + b, 0); // returns 3
[1, 1, 1].reduce((a, b, c, d) => {
if (c === 1 && b < 3) {
return a + b + 1;
}
return a + b;
}, 0); // now returns 4
Keep in mind: you cannot reassign the array parameter directly
请记住:您不能直接重新分配数组参数
[1, 1, 1].reduce( (a, b, c, d) => {
if (c === 0) {
d = [1, 1, 2];
}
return a + b;
}, 0); // still returns 3
however (as pointed out below) you CAN affect the outcome by changing the array's contents:
但是(如下所述)您可以通过更改数组的内容来影响结果:
[1, 1, 1].reduce( (a, b, c, d) => {
if (c === 0) {
d[2] = 100;
}
return a + b;
}, 0); // now returns 102
回答by Pawe?
As the promise
s have resolve
and reject
callback arguments, I created the reduce
workaround function with the break
callback argument. It takes all the same arguments as native reduce
method, except the first one is an array to work on (avoid monkey patching). The third [2] initialValue
argument is optional. See the snippet below for the function
reducer.
由于promise
■找resolve
和reject
回调的论据,我创建了reduce
与解决方法函数break
回调参数。它采用与本机reduce
方法相同的所有参数,除了第一个是要处理的数组(避免猴子修补)。第三个 [2]initialValue
参数是可选的。有关function
减速器,请参阅下面的代码段。
var list = ["w","o","r","l","d"," ","p","i","e","r","o","g","i"];
var result = reducer(list,(total,current,index,arr,stop)=>{
if(current === " ") stop(); //when called, the loop breaks
return total + current;
},'hello ');
console.log(result); //hello world
function reducer(arr, callback, initial) {
var hasInitial = arguments.length >= 3;
var total = hasInitial ? initial : arr[0];
var breakNow = false;
for (var i = hasInitial ? 0 : 1; i < arr.length; i++) {
var currentValue = arr[i];
var currentIndex = i;
var newTotal = callback(total, currentValue, currentIndex, arr, () => breakNow = true);
if (breakNow) break;
total = newTotal;
}
return total;
}
And here is the reducer
as an Array method
modified script:
这是reducer
作为数组method
修改的脚本:
Array.prototype.reducer = function(callback,initial){
var hasInitial = arguments.length >= 2;
var total = hasInitial ? initial : this[0];
var breakNow = false;
for (var i = hasInitial ? 0 : 1; i < this.length; i++) {
var currentValue = this[i];
var currentIndex = i;
var newTotal = callback(total, currentValue, currentIndex, this, () => breakNow = true);
if (breakNow) break;
total = newTotal;
}
return total;
};
var list = ["w","o","r","l","d"," ","p","i","e","r","o","g","i"];
var result = list.reducer((total,current,index,arr,stop)=>{
if(current === " ") stop(); //when called, the loop breaks
return total + current;
},'hello ');
console.log(result);
回答by luxigo
If you want to chain promises sequentially with reduce using the pattern below:
如果您想使用以下模式将 promise 与 reduce 顺序链接:
return [1,2,3,4].reduce(function(promise,n,i,arr){
return promise.then(function(){
// this code is executed when the reduce loop is terminated,
// so truncating arr here or in the call below does not works
return somethingReturningAPromise(n);
});
}, Promise.resolve());
But need to break according to something happening inside or outside a promise things become a little bit more complicated because the reduce loop is terminated before the first promise is executed, making truncating the array in the promise callbacks useless, I ended up with this implementation:
但是需要根据promise内部或外部发生的事情来中断事情变得有点复杂,因为reduce循环在第一个promise执行之前终止,使得在promise回调中截断数组无用,我最终得到了这个实现:
function reduce(array, promise, fn, i) {
i=i||0;
return promise
.then(function(){
return fn(promise,array[i]);
})
.then(function(result){
if (!promise.break && ++i<array.length) {
return reduce(array,promise,fn,i);
} else {
return result;
}
})
}
Then you can do something like this:
然后你可以做这样的事情:
var promise=Promise.resolve();
reduce([1,2,3,4],promise,function(promise,val){
return iter(promise, val);
}).catch(console.error);
function iter(promise, val) {
return new Promise(function(resolve, reject){
setTimeout(function(){
if (promise.break) return reject('break');
console.log(val);
if (val==3) {promise.break=true;}
resolve(val);
}, 4000-1000*val);
});
}