如何迭代对象中所有唯一的条目对?

时间:2012-05-08 19:37:06

标签: javascript iteration javascript-objects

我目前有一个数组数据结构,我这样迭代,在每个唯一的元素对上调用foo

for(var i = 0; i < arr.length; i++) {
    for(var j = i + 1; j < arr.length; j++) {
        foo(arr[i], arr[j]);
    }
}

但是,我意识到我宁愿使用对象而不是数组,因为我可以很容易地按名称添加和删除元素。

但是,我看不到一种明显的方法来迭代这样的对象。我能得到的最接近的是:

for(i in obj) {
    for(j in obj) {
        foo(obj[i], obj[j]);
    }
}

显然,这将每对做两次,甚至产生一对相同的元素。有没有一种简单的方法可以像我在第一个代码示例中的数组中那样迭代对象?

更新

jsperf上对解决方案进行性能测试。

5 个答案:

答案 0 :(得分:5)

我的解决方案最初是作为评论写的:

在内部循环中添加if (i < j)条件。它可能不是最好的解决方案,但只要foo函数对foo(2, 10)foo(10, 2)执行相同操作,它就会起作用:

for(i in obj) {
    for(j in obj) {
        if (i < j) {
            foo(obj[i], obj[j]);
        }
    }
}

答案 1 :(得分:2)

假设我理解你的问题......也许检查一下外循环是否已经访问过该值?

var visited = {}
for(i in obj) {
    visited[i] = true;
    for(j in obj) {
        if(j in visited){ continue; }
        foo(obj[i], obj[j]);
    }
}

答案 2 :(得分:2)

使用Object.keys()以数组的形式获取密钥列表:

keys = Object.keys();
for(i=0;i<keys.length;i++) {
    for(j=i+1;j<keys.length;j++) {
        foo(obj[keys[i]], obj[keys[j]]);
    }
}

答案 3 :(得分:2)

也许您可以尝试取消设置未使用的对象:

for(i in obj) {
    var a = obj[i];
    delete obj[i];
    for(j in obj) {
        foo(a, obj[j]);
    }
}

http://jsfiddle.net/bXcvb/

如果您需要原创obj,请参阅:How do I correctly clone a JavaScript object?

答案 4 :(得分:1)

您可以将对象键推送到数组中:

var obj_keys = [];
for (i in obj) {
  obj_keys.push(i);
}

for(i = 0; i < obj_keys.length; ++i) {
    for(j = i + 1; j < obj_keys.length; ++j) {
        foo(obj[obj_keys[i]], obj[obj_keys[j]]);
    }
}