Neatpixels
Neatpixels

Reputation: 97

Sorting array of objects into an array of paired objects with Javascript

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

Answers (3)

trizin
trizin

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

maioman
maioman

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

danh
danh

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

Related Questions