Does anyone know how to group nested arrays in Javascript like this? (can be vanilla or lodash method) (I work on Reactjs)
from
[[ 5, '103' ], [ 3, '104' ], [ 1, '105' ], [ 1, '106' ], [ 2, '107' ], [ 1, '108' ], [ 5, '109' ], [ 3, '110' ]]
to
{5: ['103','109'], 3: ['104','110'], 2: ['107'], 1: ['105','106','108']}
or
[[5, ['103','109']], [3, ['104','110']], [2, ['107']], [1, ['105','106','108']]]
Thank you
CodePudding user response:
I'm sure we can find a couple of lodahs
functions that will solve the problem together. But I think the easiest way to go about is a custom Array reducer.
const array = [[ 5, '103' ], [ 3, '104' ], [ 1, '105' ], [ 1, '106' ], [ 2, '107' ], [ 1, '108' ], [ 5, '109' ], [ 3, '110' ]];
const result = array.reduce((acc, [key, value]) => ({
...acc,
[key]: [
...acc[key] || [],
value,
]
}), {});
console.log(result)
CodePudding user response:
Use _.groupBy()
the _.head()
(the 1st element of the array), and then map the values and extract the last parameter from each of the sub-arrays in the group.
Note: since we're grouping the array into an object, and the keys are integers, the order of the keys would be numeric ascending.
const { mapValues, groupBy, head, map, last } = _;
const array = [[ 5, '103' ], [ 3, '104' ], [ 1, '105' ], [ 1, '106' ], [ 2, '107' ], [ 1, '108' ], [ 5, '109' ], [ 3, '110' ]];
const result = mapValues(
groupBy(array, head),
arr => map(arr, last)
);
console.log(result);
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG ljU96qKRCWh quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Without lodash you can reduce the array to a Map
, and then convert the Map's to an array using Array.from()
or to an object using Object.fromEntries()
.
Note: A Map preserves the order of insertion, even for integer keys, and converting the Map to an array of arrays would also maintain the original order.
const array = [[ 5, '103' ], [ 3, '104' ], [ 1, '105' ], [ 1, '106' ], [ 2, '107' ], [ 1, '108' ], [ 5, '109' ], [ 3, '110' ]];
const map = array.reduce((acc, [key, val]) => {
if(!acc.has(key)) acc.set(key, []);
acc.get(key).push(val);
return acc;
}, new Map());
console.log(Array.from(map)); // convert the Map to an array
console.log(Object.fromEntries(map)) // convert the Map to an object
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG ljU96qKRCWh quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
CodePudding user response:
If you need to group like objects, try this
function group(inarr){
let outarr = inarr.reduce((r,a)=>{
if(!r[a[0]]) r[a[0]] = [];
r[a[0]].push(a[1])
return r;
}, {});
console.log(outarr)
}
CodePudding user response:
It can be done in vanillaJS by looping the array in forEach
loop and for each cycle add the value to the object.
const toBeGrouped = [[ 5, '103' ], [ 3, '104' ], [ 1, '105' ], [ 1, '106' ], [ 2, '107' ], [ 1, '108' ], [ 5, '109' ], [ 3, '110' ]]
let grouped = {};
let k;
let value;
toBeGrouped.forEach((item) => {
k = item[0];
value = item[1];
//check if the object key exists, then check is an array, then check if the current value is in the
if (grouped[k] && Array.isArray(grouped[k]) && !grouped[k].includes(value)) {
grouped[k].push(value);
} else {
grouped[k] = [value];
}
});
console.log(grouped)