Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

128
Visualizações
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 Respostas
Responde à pergunta

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 Relatório

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda