如何分配尚未分配的最低编号

时间:2017-12-24 03:26:22

标签: javascript algorithm numbers

我正在做的是动态创建元素并将它们附加到页面。元素需要有id,因此我在创建元素时为每个元素分配一个数字id。但是,元素可以并且将以非线性方式移除,因此您最终可能会在值之间出现间隙......

一个假设情景:13451622

在上面的例子中,如果我要创建一个元素,我想将2指定为id

另一个假设情景:345

在这种情况下,应将1指定为id

我已经编写了下面的代码,它应该可以正常工作,但我觉得它不必要地复杂。 有没有人知道如何改进它?!

const divs = element.getElementsByTagName('div')
for (let i = 0; i < divs.length; i++) {
  if (i > 0 && Number(divs[i].id) > Number(divs[i-1].id)+1 ) {
    return Number(divs[i-1].id)+1
    break
  } else if (i === divs.length-1) {
    return Number(divs[divs.length-1].id)+1
  } else if (Number(divs[0].id) > 1) {
    return 1
    break
  } else if (divs.length === 1 && Number(divs[0].id) === 1) {
    return 2
  } else if (divs.length === 1 && Number(divs[0].id) !== 1) {
    return 1
  }
}

我选择接受elsyr的建议并跟踪ID。这将允许我实现以下代码,根据具体情况,这是最佳的。

const lowestNum = lowestId()
div.id = lowestNum
numericalIds[lowestNum-1] = lowestNum

function lowestId(){
  for (let i = 0; i < numericalIds.length; i++) {
    if (!numericalIds[i]) {
      return i+1
    } else if (i === numericalIds.length-1) {
      return numericalIds[numericalIds.length-1]+1
    }
  }
  return 1
}

我只需要在从页面中删除元素之前更新数组。

numericalIds[/*numerical value of id*/-1] = 0 // or null or undefined

这将始终创建具有尚未分配的最小数值且不小于1的ID。

4 个答案:

答案 0 :(得分:4)

如果我们在谈论算法的复杂性,那么您的实现最糟糕的情况是O(n)。如果您想做得更好,您可能需要使用更合适的数据结构来存储您的ID。

priority queue / min heap这样的东西会好一点,但你也说你的相对简单的循环已经太复杂了 - 你必须愿意找到一个好的图书馆或自己写出来,这不一定更简单。我不会在这里写一个实现,因为我觉得这不属于这样一个帖子的范围。

假设我们有这个“免费”的概念。 ID和&#39;采取的&#39; ID,我们在免费提供“{1}}时”我们提供了一个ID和insert&#39;一个ID,使用上面的DS允许我们将最坏情况复杂度降低到pop,而不是遍历整个数组。它看起来像这样(省略实际的O(logn)实现):

minHeap

请注意,这些是最坏情况 运行时的复杂性,我们甚至没有谈及内存注意事项

如果不了解您的应用程序以及您的数据是如何形成的,那么很难做出最终的全部建议。如果你只存储1-50和99%的ID,你的应用程序只使用1-10,那么可能只需要坚持你现在的功能。

答案 1 :(得分:2)

这是一种更实用的方法,它应该做你需要的。它基本上利用了稀疏数组。

&#13;
&#13;
return fetch()
&#13;
// Find all DOM elements with ids in the container.
const idElements = document.body.querySelectorAll('#container div[id]');

// Get all ids from the DOM elements.
// Note: first have to convert to a real array ([...idElements])
const allIds = [...idElements].map(domElement => parseInt(domElement.id));

// Filter out non-numbers.
const numericIds = allIds.filter(id => Number.isInteger(id));

// Creates a sparse array, e.g. [undefined, true, undefined].
// (The array index of undefined values are available id slots)
const arrayWithGaps = numericIds.reduce((accum, val) => {
  accum[val] = true;
  return accum;
}, []);

// Find the first empty index - this will be the lowest ID available.
const lowestAvailableId = arrayWithGaps.findIndex(val => typeof val === 'undefined');

console.log(lowestAvailableId);
&#13;
&#13;
&#13;

编辑:如果<div id="container"> <div id="0"></div> <div id="1"></div> <div id="3"></div> <div id="4"></div> <div id="5"></div> <div id="16"></div> <div id="22"></div> </div>有点外来或可读性较差,则可以使用forEach。实际上,无论如何它可能更有意义:

reduce

答案 2 :(得分:1)

您可以执行以下操作:

&#13;
&#13;
let el = document.querySelectorAll('div:not(#container)');
let elArray = [...el].map(i=>i.getAttribute('id'));
var arrayLength = Math.max.apply(Math, elArray);
var missing = [];

for ( var i = 1; i <= arrayLength; i++ ) {
    if ( elArray.indexOf(i.toString()) < 0 ) {
        missing.push(i);
    }
}
missing = missing.map(item => parseInt(item));
var min = Math.min.apply(Math, missing);
console.log('Lowest possible id is: ', min);

// Create element
var div = document.createElement("DIV");
div.setAttribute('id', min);
var container = document.getElementById('container');
container.appendChild(div);
document.getElementById(min.toString()).innerHTML = min;
&#13;
<div id="container">
  <div id="1">1</div>
  <div id="3">3</div>
  <div id="4">4</div>
  <div id="5">5</div>
  <div id="16">16</div>
</div>
&#13;
&#13;
&#13;

答案 3 :(得分:1)

相当直接的方法并不需要花哨的逻辑

&#13;
&#13;
const elems = document.querySelector('#container').children;

const getNextId = (els) => {
  let next = 1;
  if (elems) {// skip this if no existing elements
    const set = new Set([...els].map(({id}) => +id));
    while (set.has(next)) {
      next++;
    }
  }
  return next;
}

console.log('Next id: ', getNextId(elems))
&#13;
<div id="container">
  <div id="2">2</div>
  <div id="1">1</div>
  <div id="3">3</div>
  <div id="4">4</div>
  <div id="5">5</div>
  <div id="16">16</div>
  <div id="22">22</div>
</div>
&#13;
&#13;
&#13;