统计数组中与另一个对象匹配的对象数量

3

现在我正在做类似如下的事情来匹配数组中的对象:

for (var key in users)
{
if (users[key].userID==session)
{
 //do whatever
}
}

但我需要弄清楚这个匹配项出现的次数,如果只匹配一次,那么我希望它触发事件(在“//do whatever”处)

5个回答

4
您可以像这样使用array.filter方法
users.filter(function(a){return (a.userID==session)}).length == 1;

尽管用户需要运行现代浏览器 (js 1.6) 或使用 polyfill 进行过滤方法。

你知道这种方法比之前的方法更有效率吗?我问这个是因为浏览器的问题。 - Dylan Cross
这将创建一个新的数组,并为每个元素调用一个函数。虽然调用函数的开销特别低,但我非常怀疑它比普通循环更有效率。 - ThiefMaster
在jsperf.com上编写一个测试。 - Kevin Ennis
我怀疑它是否更有效率,我的建议出于简洁而非性能考虑。 - Sam Greenhalgh

4

这个操作在找到2个匹配项后立即停止搜索。

var count= 0;
for(var key in users){
    if(users[key].userID== session)++count;
    if(count== 2) break;
}
if(count== 1){
    //do whatever
}

这个回答真是太棒了,我点了赞(还试图给自己的回答点踩)。我不删除我的回答的唯一原因是它很有趣...我不知道为什么总是错过简单问题的简单解决方案。 - ajax333221

2

只需增加一个变量并在循环后检查它是否等于1

var matched = 0;
for (var key in users) {
    if (users[key].userID==session) {
        matched++;
    }
}

if (matched == 1) {
    // do something
}

好的,谢谢。这就是我打算做的方式,但我不确定是否有更有效的方法。 - Dylan Cross
1
据我所记,可能比这个稍微快一点的唯一方法是使用Object.keys()生成一个数组,然后用for循环迭代。但它只是稍微快了一点点,并且不支持旧版浏览器。除非你的对象有像10万个成员那么多,否则效率实际上不应该是一个巨大的问题。 - Kevin Ennis
是的,没错。我一直在从头开始重建我的网站,使其更加高效,因此我总是寻找尽可能高效的解决方案。因为每个部分稍微更高效一点的累积起来就会很明显。 - Dylan Cross

1

如果你担心性能问题,你可能想要查看这个:

function isOnce(itm,arr){
    var first_match=-1;
    for(var i=0,len=arr.length;i<len;i++){
        if(arr[i]===itm){
            first_match=i;
            break;
        }
    }
    if(first_match!=-1){
        var last_match=-1;
        for(i=arr.length-1;i>first_match;i--){
            if(arr[i]===itm){
                last_match=i;
                break;
            }
        }
        if(last_match==-1){
            return true;
        }
    }
    return false;
}

当满足以下两个条件时,您将会注意到节省:

  • 有2个或更多匹配项
  • 第一个和最后一个匹配项之间至少相隔1个空格

换句话说,您永远不需要循环处理第一个和最后一个匹配项之间的元素。因此,最理想的情况是:

arr=["a", ...(thousands of items here)... ,"a"];// you only looped 2 times!

其实我从来没有考虑过在匹配超过一次后停止,因为剩下的都是多余的,所以在第一个答案中添加 "if(count<1){//continue}" 是否基本上具有相同的效率呢? - Dylan Cross
@DylanCross,你不能在循环内部放置if语句,你需要等待循环完成计数。 - ajax333221
我不明白胜利在哪里。如果数组是["a", "a", (成千上万的项)],那么你的方法比找到第二个匹配项后跳出循环要慢得多,而且比必要的复杂得多。 - wheresrhys
@wheresrhys 我更新了我的答案,去掉了不必要的循环。现在,在“最糟糕”的情况下,我的代码将执行与普通代码相同数量的循环。 - ajax333221

0

我有一种感觉,可能在你的问题中漏掉了什么,但如果我理解正确,这应该可以工作,并且非常高效,因为循环会在找到第二个匹配项后立即停止。

var firstMatch = null;

for (var key in users) {
  if (users[key].userID==session) {
    if (firstMatch) { // if a previous match was found unset it and break the loop
      firstMatch = null;
      break;
    } else { // else set it
      firstMatch = users[key];
    }
  }
}

if (firstMatch) {
    doSomethingTo(firstMatch); // maybe you don't need to pass in firstMatch, but it's available if you need to
}

或者以下循环使用更少的代码完成与上面相同的操作

for (var key in users) {
  if (users[key].userID==session) {
    firstMatch = (firstMatch) ? null : users[key];
    if(!firstMatch) break;
  }
}

我尝试了你的第二个例子,但是我还没有成功让它工作。 - Dylan Cross

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接