简体   繁体   中英

Reduce an array based on closeness of numbers within objects

I have an array that looks like this:

[  
  { "begin": 870, "end": 889, "spanType": ["plan", "gt-plan"] },
  { "begin": 890, "end": 925, "spanType": ["plan", "gt-plan"] },
  { "begin": 926, "end": 938, "spanType": ["plan", "gt-plan"] },
  { "begin": 939, "end": 958, "spanType": ["plan", "gt-plan"] },
  { "begin": 7732, "end": 7790, "spanType": ["plan", "gt-plan"] },
  { "begin": 7791, "end": 7879, "spanType": ["plan", "gt-plan"] }
]

I need to loop through this and create an array that looks like this:

[  
  { "begin": 870, "end": 958, "spanType": ["plan", "gt-plan"] },
  { "begin": 7732, "end": 7879, "spanType": ["plan", "gt-plan"] }
]

Basically, if a span.end is within 3 of the next span.begin, merge the two spans together .

Here is what I have now (not working) see fiddle :

spans.forEach(function(d,i) {
    if (i+1 <= spans.length - 1) {
    if (spans[i+1].begin <= d.end + 3) {
    d.end = spans[i+1].end;
     newSpans.push(d);
  }
    else {
        newSpans.push(spans[i]);
    }
  }
});

see fiddle

At first i would sort the spans so that we don't need to check all elements over and over:

spans.sort((a,b) => a.begin - b.begin);

Now we can easily go through and merge:

const result = [];
result.push(spans.reduce((prev,curr) => {
 if(prev.end < curr.begin - 1){
  result.push(prev);
  return Object.assign({},curr);
 }
 prev.end = Math.max(prev.end, curr.end);
 return prev;
}));

Try it

With sorted data, you could check the last inserted element with the actual element and if the delta is smaller than the wanted number, then adjust the end value.

This proposal mutates the original array. If that is not wanted, you need to get a copy of the object on pushing.

 var array = [{ begin: 870, end: 889, spanType: ["plan", "gt-plan"] }, { begin: 890, end: 925, spanType: ["plan", "gt-plan"] }, { begin: 926, end: 938, spanType: ["plan", "gt-plan"] }, { begin: 939, end: 958, spanType: ["plan", "gt-plan"] }, { begin: 7732, end: 7790, spanType: ["plan", "gt-plan"] }, { begin: 7791, end: 7879, spanType: ["plan", "gt-plan"] }], result = array.reduce(function (r, o, i) { if (!i || o.begin - r[r.length - 1].end >= 3) { r.push(o); } else { r[r.length - 1].end = o.end; } return r; }, []); console.log(result); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

 const data = [ { "begin": 870, "end": 889, "spanType": ["plan", "gt-plan"] }, { "begin": 890, "end": 925, "spanType": ["plan", "gt-plan"] }, { "begin": 926, "end": 938, "spanType": ["plan", "gt-plan"] }, { "begin": 939, "end": 958, "spanType": ["plan", "gt-plan"] }, { "begin": 7732, "end": 7790, "spanType": ["plan", "gt-plan"] }, { "begin": 7791, "end": 7879, "spanType": ["plan", "gt-plan"] } ]; // your range, representing how close an end has to be to a begin to merge const RANGE = 3; // iterate through the data still available for (let i = 0; i < data.length - 1; i++) { // check if we should merge the current data object with the next one // based on the defined range if (data[i].end >= data[i+1].begin - RANGE) { // we'll merge the current object into the next one. // first, we'll set the begin value of the next object to // the one that's being merged into it data[i+1].begin = data[i].begin; // now we push the current object's spanType entries into the next object Array.prototype.push.apply(data[i+1].spanType, data[i]); // finally we remove the current object from the list as it has been // fully merged data.splice(i, 1); // we removed an element, so we'll go one back in the list i--; } } console.log(data); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM