Home > Blockchain >  How to group array to i-th iteration based on start and end values and reduce
How to group array to i-th iteration based on start and end values and reduce

Time:07-21

In the below sentence In the word Asteroid A at 0 and d at 7 position after that space is counted as 8. just for a clear picture I have lot of space below.

 // 0-7,     9-10,  12,  14-18, 20-26,   28-31,  33-37,  39-41,  43-46
 // Asteroid is      a   rocky  objects  that    orbit   the     Sun

Now, I have an object with word a rocky at 12 - 19 here 19th is blank space.

   {
      "start_offset": 12,
      "end": 19,
      "text": "a rocky",
      "entity_type": "adjective",
    },

Now, I should find all the words which falls between this start and end and push that into the above object under a key splits like below.

           {
              "start_offset": 12,
              "end": 19,
              "text": "a rocky",
              "entity_type": "adjective",
              "splits": [
                {
                  "start_offset": 14,
                  "end": 19,
                  "text": "rocky",
                  "entity_type": "adjective",
                },
              ]
            }, 

This Iteration I need to do n number of times and finally should group all the elements as given in the output.

Right now I have tried something like below with close results but still need lot of improvement. can anyone guide me please

const res = arr.reduce((pv, cv) => {
    const [{ start_offset, end }] = arr
      .filter((s) => (s.start_offset <= cv.start_offset) && (s.end >= cv.end))
      .sort((s1, s2) => (s2.end - s2.start_offset) - (s1.end - s1.start_offset));
      
    const hash = `${start_offset}-${end}`;
    pv[hash] = pv[hash]
      ? { ...pv[hash], splits: [...pv[hash].splits, cv] }
      : { start_offset, end, splits: [cv] };
    
    return pv;
}, {});
const result = Object.values(res);
console.log(result)

Given Input:

let arr = [
    {
      "start_offset": 0,
      "end": 38,
      "text": "Asteroid is a rocky objects that orbit",
      "entity_type": "adjective",
    },
    {
      "start_offset": 12,
      "end": 19,
      "text": "a rocky",
      "entity_type": "adjective",
    },
    {
      "start_offset": 14,
      "end": 27,
      "text": "rocky objects",
      "entity_type": "adjective",
    },
    {
      "start_offset": 20,
      "end": 32,
      "text": "objects that",
      "entity_type": "adjective",
    },
    {
      "start_offset": 14,
      "end": 19,
      "text": "rocky",
      "entity_type": "adjective",
    },
    {
      "start_offset": 20,
      "end": 27,
      "text": "objects",
      "entity_type": "adjective",
    },
    {
      "start_offset": 33,
      "end": 47,
      "text": "orbit the Sun",
      "entity_type": "adjective",
    },
    {
      "start_offset": 43,
      "end": 47,
      "text": "Sun",
      "entity_type": "adjective",
    }
  ]

Expected output:

  let output = [
    {
      "start_offset": 0,
      "end": 38,
      "text": "Asteroid is a rocky objects that orbit",
      "entity_type": "adjective",
      "splits": [
            {
              "start_offset": 12,
              "end": 19,
              "text": "a rocky",
              "entity_type": "adjective",
              "splits": [
                {
                  "start_offset": 14,
                  "end": 19,
                  "text": "rocky",
                  "entity_type": "adjective",
                },
              ]
            },
            {
              "start_offset": 14,
              "end": 27,
              "text": "rocky objects",
              "entity_type": "adjective",
              "splits": [
                {
                  "start_offset": 20,
                  "end": 27,
                  "text": "objects",
                  "entity_type": "adjective",
                },
              ]
            },
            {
              "start_offset": 20,
              "end": 32,
              "text": "objects that",
              "entity_type": "adjective",
            },
      ]
    },
    {
      "start_offset": 33,
      "end": 47,
      "text": "orbit the Sun",
      "entity_type": "adjective",
    },
    {
      "start_offset": 43,
      "end": 47,
      "text": "Sun",
      "entity_type": "adjective",
    }
 ]

CodePudding user response:

You could sort the array in advance and reduce the array by looking to start and end ranges for smaller levels until a sub level is found.

const
    data = [{ start_offset: 0, end: 38, text: "Asteroid is a rocky objects that orbit", entity_type: "adjective" }, { start_offset: 12, end: 19, text: "a rocky", entity_type: "adjective" }, { start_offset: 14, end: 27, text: "rocky objects", entity_type: "adjective" }, { start_offset: 20, end: 32, text: "objects that", entity_type: "adjective" }, { start_offset: 14, end: 19, text: "rocky", entity_type: "adjective" }, { start_offset: 20, end: 27, text: "objects", entity_type: "adjective" }, { start_offset: 33, end: 47, text: "orbit the Sun", entity_type: "adjective" }, { start_offset: 43, end: 47, text: "Sun", entity_type: "adjective" }],
    result = data
        .sort((a, b) => a.start_offset - b.start_offset || b.end - a.end)
        .reduce((r, { ...o }) => {
            let temp,
                child = { split: r };
            do {
                temp = child;
                temp.split ??= [];
                child = temp.split.find(q => q.start_offset <= o.start_offset && q.end >= o.end);
            } while (child)
            temp.split.push(o);            
            return r;
        }, []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

  • Related