Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

120
Vistas
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 Respuestas
Responde la pregunta

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 Denunciar

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 Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda