Dado el siguiente conjunto de datos
const data = [ { id: 1, name: "zoro", specie: "dog", age: 3, size: "big", location: { city: "city 1", town: "city 1", }, }, { id: 2, name: "nami", specie: "dog", age: 5, size: "small", location: { city: "city 1", town: "city 11", }, }, { id: 3, name: "ocho", specie: "cat", age: 9, size: "small", location: { city: "city x", town: "city x", }, }, ]; Estoy tratando de obtener resúmenes de una variedad de objetos a través de algunas de sus propiedades. El detalle es que algunos valores de esas propiedades son otros objetos por ejemplo location
Para obtener el resumen hice lo siguiente
function tally(array, key) { return array.reduce((previous, current) => { previous[current[key]] = (previous[current[key]] || 0) + 1; return previous; }, {}); }De esta forma obtengo los siguientes resultados
const specieTally = tally(data, "specie"); // { dog: 2, cat: 1 } const ageTally = tally(data, "age"); // { '3': 1, '5': 1, '9': 1 } const sizeTally = tally(data, "size"); // { big: 1, small: 2 } const locationTally = tally(data, "location.city"); // { undefined: 3 } Como puede ver, el resultado de locationTally no es correcto. Para avanzar, realizo una verificación manual de este posible escenario. Ejemplo:
function tally(array, key) { return array.reduce((previous, current) => { if (key === "location.city") { previous[current["location"]["city"]] = (previous[current["location"]["city"]] || 0) + 1; } else { previous[current[key]] = (previous[current[key]] || 0) + 1; } return previous; }, {}); }Así, la salida es la siguiente:
const locationTally = tally(data, "location.city"); // { 'city 1': 2, 'city x': 1 }Esto resuelve temporalmente, pero me gustaría saber cómo se podría obtener el mismo resultado mediante programación.
Puedes intentar algo como esto:
const data = [ { id: 1, name: "zoro", specie: "dog", age: 3, size: "big", location: { city: "city 1", town: "city 1", }, }, { id: 2, name: "nami", specie: "dog", age: 5, size: "small", location: { city: "city 1", town: "city 11", }, }, { id: 3, name: "ocho", specie: "cat", age: 9, size: "small", location: { city: "city x", town: "city x", }, }, ]; function tally(array, key) { return array.reduce((previous, current) => { if (key.indexOf('.') !== -1) { let keys = key.split('.'); previous[getNestedValue(current, keys)] = (previous[getNestedValue(current, keys)] || 0) + 1; } else { previous[current[key]] = (previous[current[key]] || 0) + 1; } return previous; }, {}); } function getNestedValue(element, keys) { let value = element; keys.forEach(key => { value = value[key]; }) return value; } const locationTally = tally(data, "location.city"); console.log(locationTally);Aquí, dividimos la clave por un carácter de punto, si está presente, y luego obtenemos el valor anidado exacto, usando una función, que recorre las claves divididas y profundiza en cada iteración, hasta que llega al final. Sin embargo, es posible que desee agregar controles nulos apropiados.
Solo tienes que resolver la clave, con un array reduce
const data = [{id:1,name:'zoro',specie:'dog',age:3,size:'big',location:{city:'city 1',town:'city 1'}},{id:2,name:'nami',specie:'dog',age:5,size:'small',location:{city:'city 1',town:'city 11'}},{id:3,name:'ocho',specie:'cat',age:9,size:'small',location:{city:'city x',town:'city x'}}] , tally = (arr, key) => arr.reduce((acc, arrElm) => { let ref = key.split('.').reduce((o,k) => o[k], arrElm) acc[ref] = (acc[ref] || 0) + 1; return acc; } , {}) , specieTally = tally( data, 'specie' ) // { dog: 2, cat: 1 } , ageTally = tally( data, 'age' ) // { '3': 1, '5': 1, '9': 1 } , sizeTally = tally( data, 'size' ) // { big: 1, small: 2 } , locationTally = tally( data, 'location.city' ) // { 'city 1': 2, 'city x': 1 } ; console.log ('specieTally:', specieTally, '\nageTally:', ageTally, '\nsizeTally:', sizeTally, '\nlocationTally:', locationTally ) .as-console-wrapper {max-height: 100% !important;top: 0;} .as-console-row::after {display: none !important;}