希望更快的双向 indexOf
/lastIndexOf
函数替代方案
2015
尽管新方法 includes
很好用,但目前基本上没有支持。
我一直在想办法以替换较慢的 indexOf
/lastIndexOf
函数。已经找到了一个高效的方法,这个方法是从顶级答案中选出来的 contains
函数,由 @Damir Zekic 提交的,应该是最快的函数。但它也说基准测试是从 2008 年的数据,所以已经过时了。
我也更喜欢使用 while
而不是 for
,但我没有具体的理由,所以结束时我用了一个 for 循环写了这个函数。它也可以用 while --
来实现。
我很好奇迭代时如果同时检查数组的两端是否会更慢。显然不会,因此这个函数比得分最高的函数快约两倍。显然,它也比原生函数快。这是在实际环境中,在这里你永远不知道你正在搜索的值是在数组的开头还是结尾。
当您知道刚刚推送了一个带有值的数组时,使用 lastIndexOf 可能仍然是最好的解决方案,但如果您必须遍历大型数组并且结果可能在任何地方,那么这可能是加快速度的可靠解决方案。
双向 indexOf
/lastIndexOf
function bidirectionalIndexOf(a, b, c, d, e){
for(c=a.length,d=c*1; c--; ){
if(a[c]==b) return c;
if(a[e=d-1-c]==b) return e;
}
return -1
}
bidirectionalIndexOf(array,'value');
性能测试
https://jsbench.me/7el1b8dj80
为了测试,我创建了一个包含10万条记录的数组。
三个查询:在数组开头、中间和结尾。
我希望您也觉得这很有趣并测试一下性能。
注意:正如您所看到的,我略微修改了contains
函数以反映indexOf
和lastIndexOf
的输出(因此基本上是true
与index
和false
与-1
)。 这不应该损害它。
数组原型变量
Object.defineProperty(Array.prototype,'bidirectionalIndexOf',{value:function(b,c,d,e){
for(c=this.length,d=c*1; c--; ){
if(this[c]==b) return c;
if(this[e=d-1-c] == b) return e;
}
return -1
},writable:false, enumerable:false});
array.bidirectionalIndexOf('value');
这个函数也可以很容易地修改为返回true或false,甚至是对象、字符串或其他类型。
下面是基于while
的变体:
function bidirectionalIndexOf(a, b, c, d){
c=a.length; d=c-1;
while(c--){
if(b===a[c]) return c;
if(b===a[d-c]) return d-c;
}
return c
}
bidirectionalIndexOf(array,'value');
这怎么可能?
我认为,通过简单计算在一个数组中获取反射指数比实际进行循环迭代要快两倍。
这里有一个复杂的例子,每次迭代都要进行三个检查,但这仅在使用更长的计算时才可能实现,从而导致代码变慢。
https://web.archive.org/web/20151019160219/http://jsperf.com/bidirectionalindexof/2
~[1,2,3].indexOf(4)
将返回 0,被评估为 false,而~[1,2,3].indexOf(3)
将返回 -3,被评估为 true。 - lordvlad~
不能将值转换为布尔型,你需要使用!
。但在本例中,你需要检查是否等于-1,所以函数可能会结束返回[1,2,3].indexOf(3) === -1。~
是二进制非运算符,它会独立地翻转每个位的值。 - mcfedr[1,2,3].indexOf(4)
实际上会返回-1。正如@mcfedr指出的,~
是比特非运算符,参见ES5 11.4.8。问题在于,由于-1的二进制表示只包含1,其补码为0,这会被评估为false。任何其他数字的补码都不为零,因此为true。所以,~
可以很好地与indexOf
一起使用。 - mknecht[[1,2],[3,4]].includes([3,4])
在哪里? - mplungjan