3

En JavaScript, nombre n donné de tableaux en entrée dans ce format: (n = 2)Agrégation de valeurs d'objet de tableaux JavaScript?

array1: 
[{x: 1, y: 5},{x: 2, y: 3},{x: 3, y: 6}] 

array2: 
[{x: 1, y: 2},{x: 2, y: 6},{x: 3, y: 2}] 

Comment puis-je cumuler les valeurs Y facilement et obtenir ce tableau résultant:

arrayOutput: 
[{x: 1, y: 7},{x: 2, y: 9},{x: 3, y: 8}] 

Je vous remercie.

+0

Pouvez-vous nous donner plus d'informations sur les valeurs? Par exemple, dans votre exemple, les entrées de chaque tableau ont des valeurs uniques «x» (par exemple, le même «x» n'apparaît pas dans le même tableau). Est-ce garanti? Est-ce que 'x' est le facteur décisif pour savoir si vous combinez des valeurs' y', ou est-ce la position dans le tableau? Des choses comme ça. –

+0

@ T.J. Crowder: Vous pouvez supposer que tous les tableaux ont la même longueur avec les mêmes valeurs x uniques dans le même ordre. Le nombre de tableaux sera cependant très important, donc une fonction efficace serait très utile. Je vous remercie. – dani

+0

Ah, d'accord, ça change les choses. –

Répondre

2

Mise à jour: Le commentaire supplémentaire sur les x valeurs et leurs positions dans les tableaux ci-dessous rend le hors de propos.

Il n'y a pas de truc particulier, il vous suffit de faire une boucle dans les tableaux et de construire votre résultat. Ce n'est rien de plus qu'une boucle imbriquée. Si vous essayez d'optimiser l'efficacité sur une large gamme de moteurs JavaScript, évitez les appels de fonction inutiles.

Quelque chose le long des lignes de:

function sumYValues(arrays) { 
    var outer, inner, array, entry, sum, result, x; 

    // Create our result array with a copy of the first array 
    result = []; 
    if (arrays.length > 0) { 
     array = arrays[0]; 
     for (inner = 0; inner < array.length; ++inner) { 
      entry = array[inner]; 
      result[inner] = {x: entry.x, y: entry.y}; 
     } 

     // Add in the remaining values 
     for (outer = 1; outer < arrays.length; ++outer) { 
      array = arrays[outer]; 
      // You might want an assert here verifying that result.length == array.length 
      for (inner = 0; inner < array.length; ++inner) { 
       entry = array[inner]; 
       // You might want an assert here verifying that result[inner].x == entry.x 
       result[inner].y += entry.y; 
      } 
     } 
    } 

    return result; 
} 

Ces boucles comptent de 0 (ou 1) à array.length - 1. Vous pouvez profiler si revenir en arrière (array.length - 1 à 0 (ou 1)) est plus rapide, la plupart du temps le "jusqu'à 0". J'avais l'habitude de supposer que c'était parce qu'il était en C quand j'étais un jeune visage frais (les comparaisons à 0 sont plus rapides que les comparaisons à une autre variable), mais cette hypothèse peut ou ne peut pas être valide en JavaScript.


Il n'y a pas de raccourci particulier, il vous suffit de faire une boucle dans les tableaux, d'effectuer vos comparaisons et de construire votre résultat. Si les valeurs x sont uniques dans chaque tableau, il peut être plus facile de suivre votre somme en cours en utilisant un objet plutôt qu'un tableau et en utilisant les valeurs x comme clés, puis de les convertir en tableau lorsque vous c'est fait. .: par exemple

function sumYValues(arrays) { 
    var outer, inner, ar, entry, sum, result, x; 

    sum = {}; 
    for (outer = 0; outer < arrays.length; ++outer) { 
     ar = arrays[outer]; 
     for (inner = 0; inner < arrays.length; ++inner) { 
      entry = ar[inner]; 
      sum[entry.x] = (sum[entry.x] || 0) + entry.y; 
     } 
    } 

    result = []; 
    for (x in sum) { 
     result.push({x: x, y: sum[x]}); 
    } 

    return result; 
} 

Ce qui précède est la plupart du temps juste pour démontrer l'utilisation sum, un objet, comme une carte de x =>y valeurs, même si elle n'implémente au moins une partie de la logique de sommation ainsi.

Cette ligne peut nécessiter quelques explications:

  sum[entry.x] = (sum[entry.x] || 0) + entry.y; 

Si sum ne dispose pas d'entrée pour cette valeur x, sum[entry.x] sera undefined, qui est une valeur « Falsey ». Donc, nous utilisons le curiously-powerful || operator soit pour obtenir la valeur pour ce x de sumou0, et ensuite ajouter le y actuel de l'entrée et de stocker le résultat.

+0

Merci beaucoup :) Je vais vérifier les aspects de profilage aussi bien. – dani

+1

J.Crowder [Benchmark] (http://jsperf.com/underscore-vs-manual/3). 'inner Raynos

+0

@TJCrowder oui c'est devenu du bruit. (nettoyé) @dani en termes d'optimisation, les méthodes natives créent de nouveaux objets. Si vous voulez un nouveau tableau (comme le tableau votre retour), utilisez les méthodes natives. Si vous n'avez pas besoin d'un nouvel objet, utilisez les boucles for/while pour modifier le tableau en mémoire. – Raynos

3

Benchmark Example

Notez que le code mixte est plus rapide suivie par des boucles suivies par natif/underscore.

function createOutput(arr1, arr2, arr3 /*, ... */) { 
    return Array.prototype.reduce.call(arguments, function (prev, curr) { 
     return prev.map(function(val, index) { 
      return { 
       x: val.x, 
       y: val.y + curr[index].y 
      } 
     }); 
    }); 
} 

Suppose tableaux sont triés et contiennent toutes les valeurs de x pour 1..n sans lacunes.

Type de requiert ES5. Cela peut être échangé pour _ qui donne ce genre de fonctionnalité d'une manière croisée de navigateur.

Avec underscore il est

function createOutput() { 
    return _.reduce(arguments, function (memo, arr) { 
     return _.map(memo, function(val, index) { 
      return { x: val.x, y: val.y + arr[index].y }; 
     }); 
    }); 
} 
+0

Je pense que cela échoue le test "efficace". C'est l33t, mais c'est un * énorme * nombre d'appels de fonction, et la première chose que vous faites est de créer une copie du "très grand nombre de tableaux". :-) –

+0

@ T.J.Crowder ouais cette copie n'était pas nécessaire parce que '_' le fait de toute façon. C'est toujours 'O (N)'. Oui, il y a des frais généraux mais c'est laconique et haut niveau. Je suis sûr que le compilateur de fermeture de Google peut éliminer les bits inefficaces. – Raynos

+1

@TJCrowder il gagne réellement le test "efficace";) – Raynos