我正在做的是动态创建元素并将它们附加到页面。元素需要有id
,因此我在创建元素时为每个元素分配一个数字id
。但是,元素可以并且将以非线性方式移除,因此您最终可能会在值之间出现间隙......
一个假设情景:1
,3
,4
,5
,16
,22
。
在上面的例子中,如果我要创建一个元素,我想将2
指定为id
。
另一个假设情景:3
,4
,5
。
在这种情况下,应将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。
答案 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)
这是一种更实用的方法,它应该做你需要的。它基本上利用了稀疏数组。
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;
编辑:如果<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)
您可以执行以下操作:
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;
答案 3 :(得分:1)
相当直接的方法并不需要花哨的逻辑
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;