找出javascript数组是否包含值的最简洁有效的方法是什么?这是我知道的唯一方法:
function contains(a, obj) { for (var i = 0; i < a.length; i++) { if (a[i] === obj) { return true; } } return false; }
有没有更好更简洁的方法来实现这一点?
b4wnujal1#
使用lodash的一些功能。它简洁、准确,并具有强大的跨平台支持。被接受的答案甚至不符合要求。要求:推荐最简洁有效的方法来确定javascript数组是否包含对象。接受的答复:
$.inArray({'b': 2}, [{'a': 1}, {'b': 2}]) > -1
我的建议是:
_.some([{'a': 1}, {'b': 2}], {'b': 2}) > true
笔记:$.Inaray w
pes8fvy92#
如果您反复检查数组中是否存在对象,您可能应该查看通过在数组中执行插入排序(将新对象放在正确的位置),始终保持数组的排序将更新对象设为删除+排序插入操作,然后在数据库中使用二进制搜索查找 contains(a, obj) .
contains(a, obj)
chhkpiq43#
function inArray(elem,array) { var len = array.length; for(var i = 0 ; i < len;i++) { if(array[i] == elem){return i;} } return -1; }
如果找到,则返回数组索引;如果未找到,则返回-1
9cbw7uwe4#
ecmascript 7引入了 Array.prototype.includes .它可以这样使用:
Array.prototype.includes
[1, 2, 3].includes(2); // true [1, 2, 3].includes(4); // false
它还接受可选的第二个参数 fromIndex :
fromIndex
[1, 2, 3].includes(3, 3); // false [1, 2, 3].includes(3, -1); // true
不像 indexOf ,它使用严格的相等比较, includes 使用samevaluezero相等算法进行比较。这意味着您可以检测数组是否包含 NaN :
indexOf
includes
NaN
[1, 2, NaN].includes(NaN); // true
也不像 indexOf , includes 不跳过缺少的索引:
new Array(5).includes(undefined); // true
目前,它仍然是一个草稿,但可以进行多填充以使其在所有浏览器上工作。
ldfqzlk85#
最上面的答案假定为基本类型,但如果您想知道数组是否包含具有某种特征的对象,则array.prototype.some()是一个优雅的解决方案:
const items = [ {a: '1'}, {a: '2'}, {a: '3'} ] items.some(item => item.a === '3') // returns true items.some(item => item.a === '4') // returns false
这样做的好处是,一旦找到元素,迭代就会中止,从而避免了不必要的迭代周期。而且,它非常适合一个 if 语句,因为它返回布尔值:
if
if (items.some(item => item.a === '3')) { // do something }
Array.prototype.some()
csbfibhn6#
假设您定义了这样一个数组:
const array = [1, 2, 3, 4]
下面是三种检查是否存在错误的方法 3 在那里。他们也都回来了 true 或 false .
3
true
false
array.includes(3) // true
// Prefixing the method with '_' to avoid name clashes Object.defineProperty(Array.prototype, '_includes', { value: function (v) { return this.indexOf(v) !== -1 }}) array._includes(3) // true
const includes = (a, v) => a.indexOf(v) !== -1 includes(array, 3) // true
ebdffaop7#
下面是与javascript 1.6兼容的 Array.indexOf :
Array.indexOf
if (!Array.indexOf) { Array.indexOf = [].indexOf ? function(arr, obj, from) { return arr.indexOf(obj, from); } : function(arr, obj, from) { // (for IE6) var l = arr.length, i = from ? parseInt((1 * from) + (from < 0 ? l : 0), 10) : 0; i = i < 0 ? 0 : i; for (; i < l; i++) { if (i in arr && arr[i] === obj) { return i; } } return -1; }; }
yb3bgrhw8#
使用:
function isInArray(array, search) { return array.indexOf(search) >= 0; } // Usage if(isInArray(my_array, "my_value")) { //... }
thtygnil9#
扩展javascript Array 对象是一个非常糟糕的主意,因为您将新属性(您的自定义方法)引入到 for-in 可以中断现有脚本的循环。几年前,原型库的作者不得不重新设计他们的库实现,以删除这种东西。如果您不需要担心与页面上运行的其他javascript的兼容性,那么就去做吧,否则,我建议使用更笨拙但更安全的独立函数解决方案。
Array
for-in
9q78igpj10#
一艘班轮:
function contains(arr, x) { return arr.filter(function(elem) { return elem == x }).length > 0; }
cs7cruho11#
先开箱思考一下,如果您多次进行此调用,那么使用关联数组和Map来使用哈希函数进行查找要高效得多。https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/map
kxxlusnw12#
今天是2020.01.07,我在macos highsierra 10.13.6上对chrome v78.0.0、safari v13.0.4和firefox v71.0.0进行测试,测试了15个选定的解决方案。结论基于 JSON , Set 令人惊讶的是 find (k,n,o)是所有浏览器中速度最慢的es6 includes (f) 只有在铬上才快速基于 for (c、d)及 indexOf (g,h)在大小阵列上的所有浏览器上都非常快,因此它们可能是高效解决方案的最佳选择在循环过程中索引减少的解决方案(b)速度较慢,可能是因为cpu缓存的工作方式。当搜索的元素位于数组长度的66%位置时,我还对大数组运行了测试,并基于 for (c,d,e)给出了类似的结果(约630次/秒-但safari和firefox上的e比c和d慢10-20%)
JSON
Set
find
for
我执行了两个测试用例:对于包含10个元素的数组,以及包含1百万个元素的数组。在这两种情况下,我们都将搜索的元素放在数组中间。
let log = (name,f) => console.log(`${name}: 3-${f(arr,'s10')} 's7'-${f(arr,'s7')} 6-${f(arr,6)} 's3'-${f(arr,'s3')}`) let arr = [1,2,3,4,5,'s6','s7','s8','s9','s10']; //arr = new Array(1000000).fill(123); arr[500000]=7; function A(a, val) { var i = -1; var n = a.length; while (i++<n) { if (a[i] === val) { return true; } } return false; } function B(a, val) { var i = a.length; while (i--) { if (a[i] === val) { return true; } } return false; } function C(a, val) { for (var i = 0; i < a.length; i++) { if (a[i] === val) return true; } return false; } function D(a,val) { var len = a.length; for(var i = 0 ; i < len;i++) { if(a[i] === val) return true; } return false; } function E(a, val){ var n = a.length-1; var t = n/2; for (var i = 0; i <= t; i++) { if (a[i] === val || a[n-i] === val) return true; } return false; } function F(a,val) { return a.includes(val); } function G(a,val) { return a.indexOf(val)>=0; } function H(a,val) { return !!~a.indexOf(val); } function I(a, val) { return a.findIndex(x=> x==val)>=0; } function J(a,val) { return a.some(x=> x===val); } function K(a, val) { const s = JSON.stringify(val); return a.some(x => JSON.stringify(x) === s); } function L(a,val) { return !a.every(x=> x!==val); } function M(a, val) { return !!a.find(x=> x==val); } function N(a,val) { return a.filter(x=>x===val).length > 0; } function O(a, val) { return new Set(a).has(val); } log('A',A); log('B',B); log('C',C); log('D',D); log('E',E); log('F',F); log('G',G); log('H',H); log('I',I); log('J',J); log('K',K); log('L',L); log('M',M); log('N',N); log('O',O);
This shippet only presents functions used in performance tests - it not perform tests itself!
小数组-10个元素您可以在这里的机器上执行测试阵列大-1.000.000个元素您可以在这里的机器上执行测试
ubbxdtey13#
我使用以下方法:
Array.prototype.contains = function (v) { return this.indexOf(v) > -1; } var a = [ 'foo', 'bar' ]; a.contains('foo'); // true a.contains('fox'); // false
wi3ka0sx14#
function contains(a, obj) { return a.some(function(element){return element == obj;}) }
array.prototype.some()在第5版中添加到ecma-262标准中
kknvjkwl15#
希望更快的双向 indexOf / lastIndexOf 可供替代的
lastIndexOf
虽然新方法includes非常好,但目前支持率基本为零。很长一段时间以来,我一直在考虑替换慢速indexof/lastindexof函数的方法。我们已经找到了一种有效的方法,看看上面的答案。从那些我选择的 contains @damir zekic发布的函数应该是最快的函数。但它也指出,这些基准是从2008年开始的,因此已经过时。我也更喜欢 while 结束 for ,但不是因为特定的原因,我用for循环结束了函数的编写。这也可以通过一个 while -- .我很好奇,如果在执行迭代时检查数组的两侧,迭代是否会慢得多。显然不是,所以这个函数比最受欢迎的函数快两倍左右。显然它也比本地的快。这是在现实环境中进行的,在现实环境中,您永远不知道要搜索的值是在数组的开头还是结尾。当你知道你刚刚用一个值推送了一个数组时,使用lastindexof可能是最好的解决方案,但是如果你必须遍历大数组,结果可能无处不在,这可能是一个使事情更快的解决方案。双向索引of/lastindexof
contains
while
while --
function bidirectionalIndexOf(a, b, c, d, e){ for(c=a.length,d=c*1; c--; ){ if(a[c]==b) return c; //or this[c]===b if(a[e=d-1-c]==b) return e; //or a[e=d-1-c]===b } return -1 } //Usage bidirectionalIndexOf(array,'value');
http://jsperf.com/bidirectionalindexof作为测试,我创建了一个包含100k条目的数组。三个查询:在开始时,在中间和在数组的末尾。我希望您也会觉得这很有趣,并测试性能。注意:如您所见,我稍微修改了 contains 函数来反映indexof和lastindexof输出(因此基本上 true 和 index 及 false 具有 -1 ). 这不应该伤害它。
index
-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; //or this[c]===b if(this[e=d-1-c] == b) return e; //or this[e=d-1-c]===b } return -1 },writable:false, enumerable:false}); // Usage 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 } // Usage bidirectionalIndexOf(array,'value');
我认为在数组中获得反射索引的简单计算非常简单,比实际循环迭代快两倍。下面是一个复杂的示例,每个迭代执行三次检查,但这只有在计算时间较长的情况下才可能实现,这会导致代码速度减慢。http://jsperf.com/bidirectionalindexof/2
21条答案
按热度按时间b4wnujal1#
使用lodash的一些功能。
它简洁、准确,并具有强大的跨平台支持。
被接受的答案甚至不符合要求。
要求:推荐最简洁有效的方法来确定javascript数组是否包含对象。
接受的答复:
我的建议是:
笔记:
$.Inaray w
pes8fvy92#
如果您反复检查数组中是否存在对象,您可能应该查看
通过在数组中执行插入排序(将新对象放在正确的位置),始终保持数组的排序
将更新对象设为删除+排序插入操作,然后
在数据库中使用二进制搜索查找
contains(a, obj)
.chhkpiq43#
如果找到,则返回数组索引;如果未找到,则返回-1
9cbw7uwe4#
ecmascript 7引入了
Array.prototype.includes
.它可以这样使用:
它还接受可选的第二个参数
fromIndex
:不像
indexOf
,它使用严格的相等比较,includes
使用samevaluezero相等算法进行比较。这意味着您可以检测数组是否包含NaN
:也不像
indexOf
,includes
不跳过缺少的索引:目前,它仍然是一个草稿,但可以进行多填充以使其在所有浏览器上工作。
ldfqzlk85#
最上面的答案假定为基本类型,但如果您想知道数组是否包含具有某种特征的对象,则array.prototype.some()是一个优雅的解决方案:
这样做的好处是,一旦找到元素,迭代就会中止,从而避免了不必要的迭代周期。
而且,它非常适合一个
if
语句,因为它返回布尔值:Array.prototype.some()
完全支持:caniuse.com支持表csbfibhn6#
假设您定义了这样一个数组:
下面是三种检查是否存在错误的方法
3
在那里。他们也都回来了true
或false
.本机数组方法(自es2016起)(兼容性表)
作为自定义数组方法(es2016之前)
简单函数
ebdffaop7#
下面是与javascript 1.6兼容的
Array.indexOf
:yb3bgrhw8#
使用:
thtygnil9#
扩展javascript
Array
对象是一个非常糟糕的主意,因为您将新属性(您的自定义方法)引入到for-in
可以中断现有脚本的循环。几年前,原型库的作者不得不重新设计他们的库实现,以删除这种东西。如果您不需要担心与页面上运行的其他javascript的兼容性,那么就去做吧,否则,我建议使用更笨拙但更安全的独立函数解决方案。
9q78igpj10#
一艘班轮:
cs7cruho11#
先开箱思考一下,如果您多次进行此调用,那么使用关联数组和Map来使用哈希函数进行查找要高效得多。
https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/map
kxxlusnw12#
演出
今天是2020.01.07,我在macos highsierra 10.13.6上对chrome v78.0.0、safari v13.0.4和firefox v71.0.0进行测试,测试了15个选定的解决方案。结论
基于
JSON
,Set
令人惊讶的是find
(k,n,o)是所有浏览器中速度最慢的es6
includes
(f) 只有在铬上才快速基于
for
(c、d)及indexOf
(g,h)在大小阵列上的所有浏览器上都非常快,因此它们可能是高效解决方案的最佳选择在循环过程中索引减少的解决方案(b)速度较慢,可能是因为cpu缓存的工作方式。
当搜索的元素位于数组长度的66%位置时,我还对大数组运行了测试,并基于
for
(c,d,e)给出了类似的结果(约630次/秒-但safari和firefox上的e比c和d慢10-20%)结果
细节
我执行了两个测试用例:对于包含10个元素的数组,以及包含1百万个元素的数组。在这两种情况下,我们都将搜索的元素放在数组中间。
小数组-10个元素
您可以在这里的机器上执行测试
阵列大-1.000.000个元素
您可以在这里的机器上执行测试
ubbxdtey13#
我使用以下方法:
wi3ka0sx14#
array.prototype.some()在第5版中添加到ecma-262标准中
kknvjkwl15#
希望更快的双向
indexOf
/lastIndexOf
可供替代的2015
虽然新方法includes非常好,但目前支持率基本为零。
很长一段时间以来,我一直在考虑替换慢速indexof/lastindexof函数的方法。
我们已经找到了一种有效的方法,看看上面的答案。从那些我选择的
contains
@damir zekic发布的函数应该是最快的函数。但它也指出,这些基准是从2008年开始的,因此已经过时。我也更喜欢
while
结束for
,但不是因为特定的原因,我用for循环结束了函数的编写。这也可以通过一个while --
.我很好奇,如果在执行迭代时检查数组的两侧,迭代是否会慢得多。显然不是,所以这个函数比最受欢迎的函数快两倍左右。显然它也比本地的快。这是在现实环境中进行的,在现实环境中,您永远不知道要搜索的值是在数组的开头还是结尾。
当你知道你刚刚用一个值推送了一个数组时,使用lastindexof可能是最好的解决方案,但是如果你必须遍历大数组,结果可能无处不在,这可能是一个使事情更快的解决方案。
双向索引of/lastindexof
性能测试
http://jsperf.com/bidirectionalindexof
作为测试,我创建了一个包含100k条目的数组。
三个查询:在开始时,在中间和在数组的末尾。
我希望您也会觉得这很有趣,并测试性能。
注意:如您所见,我稍微修改了
contains
函数来反映indexof和lastindexof输出(因此基本上true
和index
及false
具有-1
). 这不应该伤害它。阵列原型变型
该函数还可以很容易地修改为返回true或false,甚至返回对象、字符串或其他内容。
这里是
while
变体:这怎么可能?
我认为在数组中获得反射索引的简单计算非常简单,比实际循环迭代快两倍。
下面是一个复杂的示例,每个迭代执行三次检查,但这只有在计算时间较长的情况下才可能实现,这会导致代码速度减慢。
http://jsperf.com/bidirectionalindexof/2