2017-10-18 17 views
1

J'essaie actuellement de mapper et de réduire les fonctions pour aplatir un tableau multidimensionnel.
Ceci est un ensemble de données exemple maquette:Réduire la matrice multidimensionnelle

data: [ 
    { 
    label: "Sort-01" 
    data: [ 
     { 
     label: "OCT-2017" 
     weight: 2304 
     }, 
     { 
     label: "NOV-2017" 
     weight: 1783 
     } 
    ] 
    }, 
    { 
    label: "Sort-02" 
    data: [ 
     { 
     label: "OCT-2017" 
     weight: 4785 
     }, 
     { 
     label: "NOV-2017" 
     weight: 102 
     } 
    ] 
    }, 
...... 
] 

Je sais pour la carte-reduce par numéro de tri que je peux utiliser:

data.map(sort => sort.data.reduce((a,b) => a.weight + b.weight)); 

Cependant, je veux réduire par mois au lieu de numéro de tri.
J'apprécierais toute aide.

Merci,
Jay

Répondre

2

utiliser le tableau carte # pour obtenir le un tableau du tableau data de propriétés, puis aplatissez avec Array#concat et spread. Utilisez Array#reduce pour recueillir les valeurs dans un Map, puis utilisez Map#values et la syntaxe de propagation pour reconvertir un tableau:

const array = [{"label":"Sort-01","data":[{"label":"OCT-2017","weight":2304},{"label":"NOV-2017","weight":1783}]},{"label":"Sort-02","data":[{"label":"OCT-2017","weight":4785},{"label":"NOV-2017","weight":102}]}]; 
 

 
const result = [... // spread the values iterator to an array 
 
    [].concat(...array.map(({ data }) => data)) // map the array into an array of data arrays 
 
    .reduce((m, { label, weight }) => { 
 
    // take item if label exists in map, if not create new 
 
    const item = m.get(label) || { label, weight: 0 }; 
 
    
 
    item.weight += weight; // add the weight 
 
    
 
    return m.set(label, item); // set the item in the map 
 
    }, new Map).values()] // get the values iterator 
 

 
console.log(result);

Voici une version spreadless:

const array = [{"label":"Sort-01","data":[{"label":"OCT-2017","weight":2304},{"label":"NOV-2017","weight":1783}]},{"label":"Sort-02","data":[{"label":"OCT-2017","weight":4785},{"label":"NOV-2017","weight":102}]}]; 
 

 
const helper = Object.create(null); 
 
const result = [].concat.apply([], array.map(({ data }) => data)) // map the array into an array of data arrays, and flatten by apply concat 
 
    .reduce((r, { label, weight }) => { 
 
    // if label is not in helper, add to helper, and push to r 
 
    if(!helper[label]) { 
 
     helper[label] = { label, weight: 0 }; 
 
     r.push(helper[label]); 
 
    } 
 
    
 
    helper[label].weight += weight; // add the weight to the object 
 
    
 
    return r; 
 
    }, []) // get the values iterator 
 

 
console.log(result);

+0

Est-il possible de le faire sans la propagation? Je ne pense pas que le projet sur lequel je travaille actuellement ait déjà propagé des opérateurs. J'obtiens une erreur "[] .concat.apply (...). Reduce (...). Values ​​(...). Slice n'est pas une fonction". – Jay

+0

J'ai ajouté une autre version sans propagation, et Map. –

1

Vous pouvez utiliser réduire ou concat (see Ori's answer) pour obtenir un tableau de données aplati. À partir de là, réaffectez le libellé de votre année en tant que clé et poids en tant que valeur. puis passez à un autre réducteur afin de totaliser vos poids par mois.

const data = [{label: "Sort-01",data: [{label: "OCT-2017",weight: 2304,},{label: "NOV-2017",weight: 1783,},],},{label: "Sort-02",data: [{label: "OCT-2017",weight: 4785,},{label: "NOV-2017",weight: 102,},],},]; 
 
const flatten = (acc, cur) => { 
 
    cur.data.forEach(val => acc.push(val)); 
 
    return acc; 
 
}; 
 
const monthMap = ({ label, weight }) => ({ [label]: weight }); 
 
const reducer = (acc, cur) => { 
 
    const key = Object.keys(cur)[0] 
 
    if (!acc.hasOwnProperty(key)) { acc[key] = 0 } 
 
    acc[key] += cur[key]; 
 
    return acc; 
 
}; 
 

 
let x = data.reduce(flatten, []).map(monthMap).reduce(reducer, {}); 
 
console.log(x);

+0

Fonctionne très bien merci! – Jay