Disons que je veux additionner a.x
pour chaque élément arr
.
arr = [{x:1},{x:2},{x:4}]
arr.reduce(function(a,b){return a.x + b.x})
>> NaN
J'ai des raisons de croire que la hache n'est pas définie à un moment donné.
Les éléments suivants fonctionnent bien
arr = [1,2,4]
arr.reduce(function(a,b){return a + b})
>> 7
Que fais-je de mal dans le premier exemple?
arr.reduce(function(a,b){return a + b})
dans le deuxième exemple.Réponses:
Après la première itération, vous retournez un nombre, puis essayez d'en obtenir la propriété
x
à ajouter à l'objet suivant, qui estundefined
et les mathématiques impliquant desundefined
résultatsNaN
.essayez de renvoyer un objet contenant une
x
propriété avec la somme des propriétés x des paramètres:Explication ajoutée à partir des commentaires:
La valeur de retour de chaque itération est
[].reduce
utilisée commea
variable dans l'itération suivante.Itération 1:
a = {x:1}
,b = {x:2}
,{x: 3}
affecté àa
au Itération 2Itération 2:
a = {x:3}
,b = {x:4}
.Le problème avec votre exemple est que vous renvoyez un littéral numérique.
1 Iteration:
a = {x:1}
,b = {x:2}
,// returns 3
commea
dans la prochaine itération2 Iteration:
a = 3
,b = {x:2}
retoursNaN
Un littéral numérique
3
n'a pas (généralement) de propriété appeléex
donc c'estundefined
etundefined + b.x
retourneNaN
etNaN + <anything>
est toujoursNaN
Clarification : je préfère ma méthode à l'autre bonne réponse dans ce fil car je suis en désaccord avec l'idée que passer un paramètre facultatif pour réduire avec un nombre magique pour sortir un nombre primitif est plus propre. Il peut en résulter moins de lignes écrites mais imo il est moins lisible.
la source
x
clé attendue pour qu'il fonctionne.Une façon plus propre d'y parvenir consiste à fournir une valeur initiale:
La première fois que la fonction anonyme est appelée, elle est appelée avec
(0, {x: 1})
et revient0 + 1 = 1
. La prochaine fois, il est appelé avec(1, {x: 2})
et revient1 + 2 = 3
. Il est ensuite appelé avec(3, {x: 4})
, enfin de retour7
.la source
reduce
.TL; DR, définissez la valeur initiale
Utiliser la déstructuration
arr.reduce( ( sum, { x } ) => sum + x , 0)
Sans déstructuration
arr.reduce( ( sum , cur ) => sum + cur.x , 0)
Avec Typescript
arr.reduce( ( sum, { x } : { x: number } ) => sum + x , 0)
Essayons la méthode de déstructuration:
La clé de ceci est la définition de la valeur initiale. La valeur de retour devient le premier paramètre de la prochaine itération.
La technique utilisée dans la première réponse n'est pas idiomatique
La réponse acceptée propose de NE PAS passer la valeur "facultative". C'est faux, car la manière idiomatique est que le deuxième paramètre soit toujours inclus. Pourquoi? Trois raisons:
1. Dangereux - Ne pas transmettre la valeur initiale est dangereux et peut créer des effets secondaires et des mutations si la fonction de rappel est négligente.
Voir
Si toutefois nous l'avions fait de cette façon, avec la valeur initiale:
Pour l'enregistrement, sauf si vous avez l'intention de muter l'objet d'origine, définissez le premier paramètre de
Object.assign
sur un objet vide. Comme ceci:Object.assign({}, a, b, c)
.2 - Meilleure inférence de type - Lorsque vous utilisez un outil comme Typescript ou un éditeur comme VS Code, vous avez l'avantage de dire au compilateur l'initiale et il peut détecter des erreurs si vous le faites mal. Si vous ne définissez pas la valeur initiale, dans de nombreuses situations, elle pourrait ne pas être en mesure de deviner et vous pourriez vous retrouver avec des erreurs d'exécution effrayantes.
3 - Respectez les foncteurs - JavaScript brille mieux lorsque son enfant fonctionnel intérieur est libéré. Dans le monde fonctionnel, il existe une norme sur la façon dont vous "pliez" ou
reduce
un tableau. Lorsque vous pliez ou appliquez un catamorphisme au tableau, vous prenez les valeurs de ce tableau pour construire un nouveau type. Vous devez communiquer le type résultant - vous devez le faire même si le type final est celui des valeurs du tableau, d'un autre tableau ou de tout autre type.Réfléchissons-y d'une autre manière. En JavaScript, les fonctions peuvent être transmises comme des données, c'est ainsi que fonctionnent les rappels, quel est le résultat du code suivant?
[1,2,3].reduce(callback)
Va-t-il retourner un numéro? Un objet? Cela rend plus clair
[1,2,3].reduce(callback,0)
En savoir plus sur les spécifications de programmation fonctionnelle ici: https://github.com/fantasyland/fantasy-land#foldable
Un peu plus de contexte
La
reduce
méthode prend deux paramètres,La
callback
fonction prend les paramètres suivantsPour la première itération,
Si
initialItem
est fourni, lareduce
fonction transmet le eninitialItem
tant queaccumulator
et le premier élément du tableau en tant queitemInArray
.Si
initialItem
n'est pas fourni, lareduce
fonction transmet le premier élément du tableau en tant queinitialItem
et le deuxième élément du tableau en tantitemInArray
que comportement déroutant.J'enseigne et recommande de toujours régler la valeur initiale de réduire.
Vous pouvez consulter la documentation sur:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
J'espère que cela t'aides!
la source
D'autres ont répondu à cette question, mais j'ai pensé lancer une autre approche. Plutôt que de passer directement à la sommation de la hache, vous pouvez combiner une carte (de la hache à x) et réduire (pour ajouter les x):
Certes, cela va probablement être un peu plus lent, mais j'ai pensé qu'il valait la peine de le mentionner en option.
la source
Pour formaliser ce qui a été souligné, un réducteur est un catamorphisme qui prend deux arguments qui peuvent être du même type par coïncidence, et retourne un type qui correspond au premier argument.
Cela signifie que le corps du réducteur doit être sur la conversion
currentValue
et la valeur actuelle duaccumulator
à la valeur du nouveauaccumulator
.Cela fonctionne de manière simple, lors de l'ajout, car l'accumulateur et les valeurs des éléments sont tous deux du même type (mais ont des objectifs différents).
Cela fonctionne simplement parce que ce sont tous des chiffres.
Nous donnons maintenant une valeur de départ à l'agrégateur. La valeur de départ doit être le type que vous attendez de l'agrégateur (le type que vous attendez comme valeur finale), dans la grande majorité des cas. Bien que vous ne soyez pas obligé de le faire (et ne devriez pas l'être), il est important de garder à l'esprit.
Une fois que vous savez cela, vous pouvez écrire des réductions significatives pour d'autres problèmes de relation n: 1.
Suppression de mots répétés:
Fournir un décompte de tous les mots trouvés:
Réduction d'un tableau de tableaux en un seul tableau plat:
Chaque fois que vous cherchez à passer d'un ensemble de choses à une valeur unique qui ne correspond pas à un 1: 1, réduire est quelque chose que vous pourriez envisager.
En fait, la carte et le filtre peuvent tous deux être mis en œuvre en tant que réductions:
J'espère que cela fournit un contexte supplémentaire pour l'utilisation
reduce
.Le seul ajout à cela, que je n'ai pas encore analysé, c'est quand on s'attend à ce que les types d'entrée et de sortie soient spécifiquement destinés à être dynamiques, car les éléments du tableau sont des fonctions:
la source
Pour la première itération, 'a' sera le premier objet du tableau, donc ax + bx renverra 1 + 2, c'est-à-dire 3. Maintenant, dans la prochaine itération, le 3 renvoyé est affecté à a, donc a est un nombre maintenant n appelant ax donnera NaN.
Une solution simple consiste d'abord à mapper les nombres dans le tableau, puis à les réduire comme ci-dessous:
ici
arr.map(a=>a.x)
fournira un tableau de nombres [1,2,4] utilisant maintenant.reduce(function(a,b){return a+b})
va simplement ajouter ces nombres sans aucun hasselUne autre solution simple consiste simplement à fournir une somme initiale égale à zéro en affectant 0 à «a» comme ci-dessous:
la source
À chaque étape de votre réduction, vous ne retournez pas de nouvel
{x:???}
objet. Vous devez donc soit faire:ou vous devez faire
la source
Dans la première étape, cela fonctionnera correctement car la valeur de
a
sera 1 et celle deb
2 mais comme 2 + 1 sera retourné et dans l'étape suivante la valeur deb
sera la valeur de retourfrom step 1 i.e 3
et ainsib.x
sera pas définie. .et undefined + anyNumber sera NaN et c'est pourquoi vous obtenez ce résultat.Au lieu de cela, vous pouvez essayer cela en donnant la valeur initiale à zéro, c'est-à-dire
la source
Si vous avez un objet complexe avec beaucoup de données, comme un tableau d'objets, vous pouvez adopter une approche pas à pas pour résoudre ce problème.
Par exemple:
Tout d'abord, vous devez mapper votre tableau dans un nouveau tableau de votre intérêt, il pourrait s'agir d'un nouveau tableau de valeurs dans cet exemple.
Cette fonction de rappel renverra un nouveau tableau contenant uniquement les valeurs du tableau d'origine et le stockera sur les valeurs const. Maintenant, vos valeurs const sont un tableau comme celui-ci:
Et maintenant, vous êtes prêt à effectuer votre réduction:
Comme vous pouvez le voir, la méthode de réduction exécute la fonction de rappel plusieurs fois. Pour chaque fois, il prend la valeur actuelle de l'élément dans le tableau et la somme avec l'accumulateur. Donc, pour résumer correctement, vous devez définir la valeur initiale de votre accumulateur comme deuxième argument de la méthode de réduction.
Vous avez maintenant votre nouvelle somme constante avec la valeur 30.
la source
réduire la fonction itère sur une collection
Se traduit par:
Pour comprendre les entrées et les sorties de la fonction "réduire", je vous suggère de consulter le code source de cette fonction. La bibliothèque Lodash a une fonction de réduction qui fonctionne exactement de la même manière que la fonction de réduction dans ES6.
Voici le lien: réduire le code source
la source
pour renvoyer une somme de tous les
x
accessoires:la source
Vous pouvez utiliser la carte et réduire les fonctions
la source
La fonction de réduction de tableau prend trois paramètres, à savoir, initialValue (par défaut c'est 0), l'accumulateur et la valeur actuelle. Par défaut, la valeur de initialValue sera "0". qui est pris par l'accumulateur
Voyons cela dans le code.
Maintenant, même exemple avec la valeur initiale:
Il en va de même pour les tableaux d'objets (la question actuelle du stackoverflow):
UNE CHOSE À NU DANS L'ESPRIT est InitialValue par défaut est 0 et peut être donné tout ce que je veux dire {}, [] et nombre
la source
la source
vous ne devez pas utiliser ax pour l'accumulateur, mais vous pouvez faire comme ceci `arr = [{x: 1}, {x: 2}, {x: 4}]
arr.reduce (fonction (a, b) {a + bx}, 0) `
la source