4

我目前有一个数组数据结构,我像这样迭代它,调用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上测试解决方案的性能。

4

5 回答 5

5

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

if (i < j)在内循环中添加条件。它可能不是最好的解决方案,但只要 foo 函数对foo(2, 10)and做同样的事情,它就可以工作foo(10, 2)

for(i in obj) {
    for(j in obj) {
        if (i < j) {
            foo(obj[i], obj[j]);
        }
    }
}
于 2012-05-08T20:29:07.930 回答
2

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

var visited = {}
for(i in obj) {
    visited[i] = true;
    for(j in obj) {
        if(j in visited){ continue; }
        foo(obj[i], obj[j]);
    }
}
于 2012-05-08T19:44:27.290 回答
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]]);
    }
}
于 2012-05-08T19:50:21.550 回答
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,请参阅:如何正确克隆 JavaScript 对象?

于 2012-05-08T19:55:20.473 回答
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]]);
    }
}
于 2012-05-08T19:47:19.893 回答