Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

117
Views
How to recompute ranges when some numbers are shuffled between lists

I have a large list of ranges:

list A = [{lower:0,upper:10}, {lower:11,upper:20}, {lower:31, upper:33}]
list B = [{lower:21,upper:30}, {lower:34,upper:9999}]

This list can accept modifications in terms of moving numbers between one another. For example:

Move numbers 13, 14 and 15 from list A to list B

The lists now change to:

list A = [{lower:0,upper:10}, {lower:11,upper:12}, {lower:14, upper:20},{lower:31, upper:33}]
list B = [{lower:13, upper:15},{lower:21,upper:30}, {lower:34,upper:9999}]

Currently I am doing this by accepting the following as input:

numbers for list A: [0,1,2,3,4,5,6,7,8,9,10,11,12,...20,31...33]
numbers for list B: [13,14,15,21,22...30,34...9999]

And then recompute the ranges from these numbers:

getRanges(numbers) {
  numbers.sort();
  let length = 1;
  let ranges = [];
  for (let i = 1; i <= numbers.length; i++) {
    if (i == numbers.length || numbers[i] - numbers[i - 1] != 1) {
      if (length == 1) {
        let upper = lower = numbers[i - length];
        ranges.push({lower, upper});
      }
      else {
        let lower = numbers[i - length];
        let upper = numbers[i - 1];
        ranges.push({lower, upper});
      }
      length = 1;
    }
    else {
      length++;
    }
  }
  return ranges;
}

The problem with this approach is, there are lists with huge ranges

list C = [{lower:5000001, upper:6999900},{lower:9000000, upper:9999999}]

And the input intent is to move a small set of numbers (Not necessarily a range) from this to a new list. For example:

Move numbers 5000010 to 5000020 from list C to list B

The lists will now look like

list A = [{lower:0,upper:10}, {lower:11,upper:12}, {lower:14, upper:20},{lower:31, upper:33}]
list B = [{lower:13, upper:15},{lower:21,upper:30}, {lower:34,upper:9999},{lower:5000010, upper:5000020},]
list C = [{lower:5000000, upper:5000009},{lower:5000021, upper:6999900},{lower:9000000, upper:9999999}]

Expanding these numbers as user inputs and recomputing them is memory intensive. Also - inputs are only a list of numbers (And not ranges)

Is there a better way to recompute ranges from list of numbers than to expect the complete list?

about 4 years ago · Juan Pablo Isaza
2 answers
Answer question

0

There is absolutely no need to expand the list of numbers and/or check them one by one. Checking if two ranges overlap and calculating the overlapping portion is fairly simple. Below is a function that:

  • Accepts an array of ranges in the form [{lower: x, upper: y}, ...]
  • And the range to remove {lower: x, upper: y}

And returns:

  • The result array
  • And removed array containing ranges that were successfully removed (could be inserted directly into the "move to" array).

function removeRange(ranges, remove) {
  let result = [];
  let removed = [];
  ranges.forEach(function(range) {
    // if this range overlaps the remove range
    if (remove.upper >= range.lower && range.upper >= remove.lower) {
      // calculate the overlapping portion
      let overlap = { lower: Math.max(range.lower, remove.lower), upper: Math.min(range.upper, remove.upper) };
      // this range needs to be split into:
      // 0 parts when fully covered by remove range
      // 1 part when remove range starts or ends inside
      // 2 parts whem remove range is fully inside
      if (overlap.lower > range.lower) {
        result.push({ lower: range.lower, upper: overlap.lower - 1 });
      }
      if (overlap.upper < range.upper) {
        result.push({ lower: overlap.upper + 1, upper: range.upper });
      }
      // the overlap has been dealt with
      removed.push(overlap);
    } else {
      result.push(range);
    }
  });
  return { result: result, removed: removed };
}

/*
 * Tests
 */

const ranges = [{ lower: 0, upper: 10 }, { lower: 11, upper: 20 }, { lower: 31, upper: 33 }];

console.log("fully inside test");
console.log(removeRange(ranges, { lower: 13, upper: 15 }));

console.log("ends inside test");
console.log(removeRange(ranges, { lower: 30, upper: 32 }));

console.log("starts inside test");
console.log(removeRange(ranges, { lower: 32, upper: 34 }));

console.log("fully covered test");
console.log(removeRange(ranges, { lower: 30, upper: 34 }));

console.log("no-op test");
console.log(removeRange(ranges, { lower: 50, upper: 60 }));

console.log("multi removal test");
console.log(removeRange(ranges, { lower: 19, upper: 32 }));
<p>Check logs in Developer Console</p>

about 4 years ago · Juan Pablo Isaza Report

0

If the case is that you have a small amount of ranges compared to numbers, it will be more effective to recalculate the ranges. Here's a short example of how the code could look like when updating a range.

jsfiddle

let listA = [{lower:0,upper:10}, {lower:11,upper:20}, {lower:31, upper:33}]
let listB = [{lower:21,upper:30}, {lower:34,upper:9999}]

const removeNumberFromList = (number, currentList) => {
  return currentList.reduce((acc, range) => {
    if (number < range.lower ||number > range.upper) {
      acc.push(range)
      return acc
    }

    if (number === range.lower) {
      acc.push([{lower: range.lower + 1, upper: range.upper}])
      return acc
    }


    if (number === range.upper) {
      acc.push([{lower: range.lower, upper: range.upper - 1}])
      return acc
    }

    if (number > range.lower && number < range.upper) {
      acc.push({lower: range.lower,upper:number - 1})
      acc.push({lower: number + 1,upper:range.upper})
      return acc
    }

    return acc
  }, [])
}

// When moving a number, remove it from the old list 
// and add it to the new list. If you want to move
// multiple numbers, do this for every number to be 
// moved. 
const updatedFromList = removeNumberFromList(13, listA)
// const updatedToList = addNumberToist(13, listB)


console.log("updatedFromList", updatedFromList);

If there are very many ranges as well, you can keep the range lists sorted and use binary search to find the ranges that is affected by a move. Maybe it is even okay to mutate the lists instead of recreating them, that depends on your use case and the amount of data you need to handle.

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!