我正在尝试实现unique(array)
函数,而不使用任何数组库方法(无.push
,.slice
或.pop
等)。我认为我非常接近解决方案,但我作为测试[2,2,3,3,4,2,2,2,2]
传递的数组正在返回[2,undefined,3,undefined,4]
(在控制台中看起来像[2, ,3, ,4]
而不是{{1} }}。知道这里发生了什么吗?我还尝试添加[2,3,4]
语句,以便在将if
分配给array[i]
之前检查returnArray[i]
是否未定义,但这不起作用。
array[i]
答案 0 :(得分:3)
试
returnArray[returnArray.length] = array[i];
代替returnArray[i] = array[i];
答案 1 :(得分:2)
你应该使用索引变量为returnArray赋值。因为returnArray和数组的长度可能不同。
function unique(array){
var index = 0;
var tempObject = {};
var returnArray = [];
for (var i = 0; i < array.length; i++){
if (!tempObject.hasOwnProperty(array[i])){
tempObject[array[i]] = true;
returnArray[index] = array[i];
index++;
}
}
return returnArray;
}
答案 2 :(得分:2)
进行锻炼。和乐趣。
我认为使用object[array[i]]
和hasOwnProperty
是作弊的。你说“不使用任何数组方法”,所以你使用对象方法,有点为什么呢?和第二个阵列?在对象键的顶部,完全失去了裸骨的精神,计算字节编码。
你需要像这个难看的难以理解的代币集合。然而非常快,只有5个额外的参考,相比之下优雅。 LOL
function unique(a){
var i,j,t,b,c
i=t=j=0
while((b=a[i])!==c){
j=0
while(j<t&&a[j]!==b)j++
if(j==t)a[t++]=b
i++
}
while(i>=t)a[i--]=c
a.length=t
return a
}
在使用length to trim();
之前写入自身和解引用更新更多详细信息,现在就是答案。
它的作用是遍历读取每个项目的数组,直到它读取一个假定为数组末尾的未定义项目。
当读取每个项目时,它会搜索先前读取的所有项目以检查是否存在匹配项。如果未找到匹配项,则将项目放回到写入位置的数组中,因为它必须是唯一的到目前为止,如果找到一个匹配然后放下该项并循环读取下一个项目。
读写索引。读取索引总是在写入索引之前或者等于写入索引,如果发现某个项目已经存在,那么该项目不会被放回到数组中,并且写入索引不会增加,从而使写入索引落后于读取索引。 / p>
在主循环结束时,writeIndex
可能会跟踪读取索引,从而在数组中留下一些不需要的项目。然后我循环遍历readIndex
(当前=== array.length)和写入索引之间的所有项目。这是严格不需要的,因为向Array length属性写一个较短的长度具有修剪数组的效果,有效地做同样的事情。我添加了它,因为我想要纯粹的挑战,而不是使用Array方法来修剪数组。 (这是javascript有些事情是不可避免的)
因此,该函数被重写以符合JSLint样式标准。
function unique(array) {
'use strict'; // required by JSLint standards and really!!... never code JS without it
// define all variables requierd
var readIndex,
searchIndex,
writeIndex,
arrayItem,
undefinedRef;
// you will notice that I do not indicate undefinedRef, it is undefined after all.
readIndex = 0; // set the read index to start of the array
writeIndex = 0; // set the write index to the start of the array
// check if the readIndex has reached the end of the array
while (array[readIndex] !== undefinedRef) {
// get the item at the current readIndex. I could have made the code shorter
// by not needing the arrayItem and just indexing the array at readIndex
// in the next loop. But indexing into an array is always slower than
// using a direct referance. Doing it this way adds a significant performance
// improvement to the function.
arrayItem = array[readIndex];
searchIndex = 0; // set the search index to the start of the array
// loop untill the search index reaches the write index or a match is found
while (searchIndex < writeIndex && array[searchIndex] !== arrayItem) {
searchIndex += 1; // increment the search index
}
// the seach index is at the write index then no match has been found
// the new item must be unique so far so add it to the array
if (searchIndex === writeIndex) {
array[writeIndex] = arrayItem; // add the item at the write index
writeIndex += 1; // increment the write index
}
// done for this item increment the readindex and loop
readIndex += 1;
}
// dereferance any unwriten array items at the end of the array.
// Dont really need this loop as setting the array length does the same thing
while (readIndex >= writeIndex) {
array[readIndex] = undefinedRef;
}
// remove the undefined items from the array by setting it lenght to the
// number of items writen back into the array.
array.length = writeIndex;
// return the array.
return array;
}
这就是你如何编写关于函数的大量内容,使它看起来很重要。
<强>更新强> 另一个不使用任何数组方法。
ES6版本效率不高但非常简单,比上面的版本慢了约20%。也使用更多的内存,但应该只看到上面一个引用计数的两倍。另外,检查重复项的作弊现在由Set.add()
处理。虽然为什么比数组索引搜索慢谁知道??
作为单行,因为它看起来不错
var unique=(a)=>{var c,i=0,s=new Set();while((b=a[i])!==c){s.add(b);a[i++]=c}return[...s]}
并扩展了一点(故意删除; {}空格,并使用未定义的c来测试undefined(数组的结尾))我假设数组中没有未定义的值。
这使用Set来剔除重复项。然后传播回到数组
var unique=(a)=>{ // arrow function
var c,i=0,s=new Set() // c undefined i=0 starting index and s a new Set
while((b=a[i])!==c){
s.add(b); // add to the set till end of array
a[i++]=c // and dereference all array items as we go.
}
return [...s] // convert to array with spread operator and return
}