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; }