Search code examples
javascriptarraysfabricjs

Convert array of objects to array of arrays grouped by values


In the fabric.js app I have elements that are divided into several groups.
The user can form an arbitrary number of groups containing an arbitrary number of elements.
The attached image shows the elements grouped into three groups, and each element shows its ID.

Canvas elements

When the user has finished creating groups, the app measures the distance between the elements and puts the elements in a "parent - child(ren)" relation.
This results in an array of objects:

var elements = [
    { "parent": 1, "children": [ 2 ] },
    { "parent": 2, "children": [ 1 ] },
    { "parent": 3, "children": [ 7 ] },
    { "parent": 4, "children": [ 5, 6 ] },
    { "parent": 5, "children": [ 4, 6, 7 ] },
    { "parent": 6, "children": [ 4, 5 ] },
    { "parent": 7, "children": [ 3, 5 ] },
    { "parent": 8, "children": [ 9 ] },
    { "parent": 9, "children": [ 8, 11 ] },
    { "parent": 10, "children": [ 11, 12 ] },
    { "parent": 11, "children": [ 9, 10 ] },
    { "parent": 12, "children": [ 10 ] }
];

Each element in a group is parent to the elements that are close to it, but at the same time it is also a child of the element closest to it.
How, in this example, to get an array with three subarrays from the "elements" array?
Each resulting subarray should contain ID's of elements that are only in that group.
The final result should be:

var groups = [
    [1, 2],
    [3, 4, 5, 6, 7],
    [8, 9, 10, 11, 12]
];

Solution

  • 1) Build sets by going over elements. For each element, check if parent is in any existing set. If no set available then create the set. Add the children to the set.
    2) Now, we have array of sets and might have intersecting sets, which need to merge.
    3) convert the array of sets into array of arrays.

    PS: I think step 2 of merge can be combined in step 1 itself.

    var elements = [
      { parent: 1, children: [2] },
      { parent: 2, children: [1] },
      { parent: 3, children: [7] },
      { parent: 4, children: [5, 6] },
      { parent: 5, children: [4, 6, 7] },
      { parent: 6, children: [4, 5] },
      { parent: 7, children: [3, 5] },
      { parent: 8, children: [9] },
      { parent: 9, children: [8, 11] },
      { parent: 10, children: [11, 12] },
      { parent: 11, children: [9, 10] },
      { parent: 12, children: [10] }
    ];
    
    const arrSets = [];
    
    elements.forEach(({ parent, children }) => {
      let set = arrSets.find(set => set.has(parent));
      if (!set) {
        set = new Set();
        set.add(parent);
        arrSets.push(set);
      }
      children.forEach(x => set.add(x));
    });
    
    const resSets = [];
    arrSets.forEach(set => {
      let curr = resSets.find(dat => [...set].some(x => dat.has(x)));
      if (!curr) {
        curr = new Set();
        resSets.push(curr);
      }
      [...set].forEach(x => curr.add(x));
    });
    
    const arr = resSets.map(set => [...set]);
    
    console.log(arr);