Este es un problema muy específico pero tengo un objeto con matrices:
let rawData = { one: ["a", "a", "a", "b", "b", "b", "c", "c", "c"], two: [1,2,3,1,2,3,1,2,3], three: [1,4,9,3,9,7,6,5,5] }y quiero escribir una función genérica que creará un conjunto de objetos anidados basados en la primera matriz (aquí a, pero me gustaría que esta función no dependa de una clave específica.
En mi primer intento, escribí una función que analiza esto en una matriz de objetos:
dataframe_for_plot = (data) => { var length var names = [] for (var name in data) { if (data.hasOwnProperty(name)) names.push(name); length = rawData[name].length; } var results = []; var item; for (var row = 0; row < length; row++) { item = {}; for (var col = 0; col < names.length; col++) { item[names[col]] = data[names[col]][row]; } results.push(item); } return results; }que produce
dataframe_for_plot(rawData) [ {one: "a", two: 1, three: 1}, {one: "a", two: 2, three: 4}, {one: "a", two: 3, three: 9}, {one: "b", two: 1, three: 3}, {one: "b", two: 2, three: 9}, {one: "b", two: 3, three: 7}, {one: "c", two: 1, three: 6}, {one: "c", two: 2, three: 5}, {one: "c", two: 3, three: 5}, ] Pero quiero aprovechar esta función para obtener el resultado deseado donde la primera clave se usa para crear objetos basados en el número único de esa clave (3 en este caso), y se crea una nueva clave de value para contener una matriz anidada de las otras teclas ( two y three en este caso, agrupadas por one )
let desired_output = [ { one:"a", values: [ {two:1, three:1}, {two:2, three:4}, {two:3, three:9} ], }, { one:"b", values: [ {two:1, three:3}, {two:2, three:9}, {two:3, three:7} ], }, { one:"c", values: [ {two:1, three:6}, {two:2, three:5}, {two:3, three:5} ], } ]Creo que mi función es un buen comienzo, ¡pero necesito un poco de ayuda para trabajar en la parte 2 anidada! ¡Gracias!
Convierta el objeto en una matriz de entradas y obtenga la key y el valor del primer vals . Reduzca el vals a un mapa. El mapa tendría un solo objeto para cada valor único de la primera matriz si los valores ( one en su caso). Luego itere la matriz de los otros valores, tome el valor respectivo de cada par [key, arr] y conviértalos en un objeto usando Object.fromEntries() .
Convierta el iterador de valores del mapa nuevamente en una matriz usando Array.from() .
const fn = obj => { const [[key, vals], ...values] = Object.entries(obj) return Array.from(vals.reduce((acc, v, i) => { if(!acc.has(v)) acc.set(v, { [key]: v, values: [] }) acc.get(v).values.push(Object.fromEntries( values.map(([k, arr]) => [k, arr[i]]) )) return acc }, new Map()).values()) } const rawData = { one: ["a", "a", "a", "b", "b", "b", "c", "c", "c"], two: [1,2,3,1,2,3,1,2,3], three: [1,4,9,3,9,7,6,5,5] } const result = fn(rawData) console.log(result) Si desea controlar el orden de las propiedades, puede pasar una matriz de order y luego crear las entradas manualmente en el orden que ha indicado:
const fn = (order, obj) => { const [[key, vals], ...values] = order.map(key => [key, obj[key]]) return Array.from(vals.reduce((acc, v, i) => { if(!acc.has(v)) acc.set(v, { [key]: v, values: [] }) acc.get(v).values.push(Object.fromEntries( values.map(([k, arr]) => [k, arr[i]]) )) return acc }, new Map()).values()) } const rawData = { one: ["a", "a", "a", "b", "b", "b", "c", "c", "c"], two: [1,2,3,1,2,3,1,2,3], three: [1,4,9,3,9,7,6,5,5] } const result = fn(['one', 'three', 'two'], rawData) console.log(result)