Reputation: 97
I have an array of objects and I want to be able to sort them by their "site" value into pairs. There can't be more that 2 objects in each child array so if there is 3 matches I get 1 child array with 2 objects and 1 child array with 1 object.
I have:
[{site:'A'}, {site:'A'}, {site:'B'}, {site:'B'}, {site:'B'}];
I want:
[[{site:'A'}, {site:'A'}],[{site:'B'}, {site:'B'}], [{site:'B'}]]
Whats the best way to do this? any help is appreciated.
Upvotes: 2
Views: 93
Reputation: 341
This should work for you
function sortArray(arr){
arr.sort((a,b)=>a.site > b.site ? 1 : -1) // Sorting the array to have consecutive values
let chunks = [];
for(let i = 0;i<arr.length;i+=2){
if(arr[i]?.site == arr[i+1]?.site) chunks.push(arr.slice(i,i+2));
else {
chunks.push([arr[i]]);
i--;
}
}
return chunks;
}
let arr = [{site:'A'}, {site:'A'}, {site:'B'}, {site:'B'}, {site:'B'}];
console.log(sortArray(arr))
Upvotes: 3
Reputation: 18762
Using reduce ;) :
const a = [{
site: 'A'
}, {
site: 'A'
}, {
site: 'B'
}, {
site: 'B'
}, {
site: 'B'
}];
var r = a.reduce((ac, x) => ({
...ac,
[x.site]: [...(ac[x.site] || []), x]
}), {})
var r2 = Object.values(r).flatMap(x =>
x.reduce((ac, z, i) => {
if (i % 2) {
ac[i - 1].push(z)
return ac
}
return [...ac, [z]]
}, []))
console.log(r2)
PS: Since this is hard to read I'd suggest to use lodash (specifically groupBy and chunk methods)
Upvotes: 2
Reputation: 62686
It's kind of a 'groupBy' operation (as seen in underscore or lodash). Those produce an object keyed by the values being grouped. Consider writing it that way for general use. To get the shape the OP is looking for, strip out the values of that result...
function groupBy(array, key) {
return array.reduce((acc, el) => {
let value = el[key];
if (!acc[value]) acc[value] = [];
acc[value].push(el);
return acc;
}, {});
}
let array = [{site:'A'}, {site:'A'}, {site:'B'}, {site:'B'}, {site:'B'}];
let grouped = groupBy(array, 'site'); // produces { A: [{site:'A'} ...], B: ... }
let groups = Object.values(grouped)
console.log(groups)
Upvotes: 0