javascript - img - title html attribute
Cómo romper en reducir método (10)
Array.every puede proporcionar un mecanismo muy natural para romper la iteración de alto orden.
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
¿Cómo puedo romper la iteración en el método reducir?
para
for (var i = Things.length - 1; i >= 0; i--) {
if(Things[i] <= 0){
break;
}
};
reducir
Things.reduce(function(memo, current){
if(current <= 0){
//break ???
//return; <-- this will return undefined to memo, which is not what I want
}
}, 0)
Como las
promise
tienen
resolve
y
reject
argumentos de devolución de llamada, creé la función de solución alternativa con el argumento de devolución de llamada.
Toma todos los mismos argumentos que el método nativo de
reduce
, excepto que el primero es una matriz para trabajar (evitar parches de mono).
El tercer argumento [2]
initialValue
es opcional.
Consulte el fragmento a continuación para ver el reductor de
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;
}
Y aquí está el
reducer
como un script modificado del
method
Array:
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);
No hay forma, por supuesto, de que la versión incorporada de
reduce
salga prematuramente.
Pero puede escribir su propia versión de reduce que utiliza un token especial para identificar cuándo se debe romper el ciclo.
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;
}
Úselo así, para sumar una matriz, pero salga cuando llegue a 99:
reduce([1, 2, 99, 3], (a, b) => b === 99 ? EXIT_REDUCE : a + b, 0);
> 3
No puede romper desde el interior de un método de reducción. Dependiendo de lo que esté tratando de lograr, podría alterar el resultado final (que es una razón por la que puede querer hacer esto)
[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
Recuerde: no puede reasignar el parámetro de matriz directamente
[1, 1, 1].reduce( (a, b, c, d) => {
if (c === 0) {
d = [1, 1, 2];
}
return a + b;
}, 0); // still returns 3
sin embargo (como se señala a continuación) PUEDE afectar el resultado al cambiar el contenido de la matriz:
[1, 1, 1].reduce( (a, b, c, d) => {
if (c === 0) {
d[2] = 100;
}
return a + b;
}, 0); // now returns 102
No use reducir. Simplemente itere en la matriz con iteradores normales (para, etc.) y explote cuando se cumpla su condición.
Otra implementación simple que llegué a resolver el mismo problema:
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
}
Puede romper cada código, y por lo tanto cada iterador de compilación, lanzando una excepción:
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
}
Puede usar funciones como algunas y siempre y cuando no le importe el valor de retorno. cada pausa cuando la devolución de llamada devuelve falso, algunas cuando devuelve verdadero:
things.every(function(v, i, o) {
// do stuff
if (timeToBreak) {
return false;
} else {
return true;
}
}, thisArg);
Si desea encadenar promesas secuencialmente con reducción utilizando el siguiente patrón:
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());
Pero la necesidad de romper de acuerdo con algo que sucede dentro o fuera de una promesa, las cosas se vuelven un poco más complicadas porque el ciclo de reducción termina antes de que se ejecute la primera promesa, lo que hace que el truncamiento de la matriz en las devoluciones de llamada de promesa sea inútil, terminé con esta implementación:
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;
}
})
}
Entonces puedes hacer algo como esto:
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);
});
}
ACTUALIZAR
Algunos de los comentaristas señalan que la matriz original está siendo mutada para romper pronto dentro de la lógica
.reduce()
.
Por lo tanto, he modificado
ligeramente
la respuesta agregando un
.slice(0)
antes de llamar a un paso de continuación
.reduce()
.
Esto es para preservar la matriz original copiando su contenido en tiempo lineal - O (n). La matriz original también se registra en la consola como prueba de que se ha conservado.
const array = ["9", "91", "95", "96", "99"];
const x = array.slice(0).reduce((acc, curr, i, arr) => { // notice the "slice(0)"
if (i === 2) arr.splice(1); // eject early
return (acc += curr);
}, "");
console.log("x: ", x, "/noriginal Arr: ", array); // x: 99195
// original Arr: [ ''9'', ''91'', ''95'', ''96'', ''99'' ]
ANTIGUO
PUEDE interrumpir cualquier iteración de una invocación .reduce () al mutar el cuarto argumento de la función reduce: "array".
No es necesario una función de reducción personalizada.
Consulte
reference
para obtener una lista completa de los parámetros
.reduce()
.
Array.prototype.reduce ((acc, curr, i, array))
El cuarto argumento es la matriz que se repite.
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
¿POR QUÉ?:
La única y única razón por la que puedo pensar en usar esto en lugar de las muchas otras soluciones presentadas es si desea mantener una metodología de programación funcional para su algoritmo y desea el enfoque más declarativo posible para lograrlo. Si su objetivo completo es REDUCIR literalmente una matriz a una primitiva no falsey alternativa (Cadena, Número, Booleano, Símbolo), entonces diría que ES el mejor enfoque.
¿POR QUÉ NO?
Hay una lista completa de argumentos para establecer los parámetros de la función NO mutante, ya que es una mala práctica.