我有一个大约15,000个javascript对象的数组。每个对象都有两个字段:
{
name : "Foo",
address : "bar@moo.com"
}
我想创建一个只存储唯一电子邮件地址和相应名称的新数组。到目前为止,我有这种方法:
// temp1 is my array of 15,000 objects
var arr = [];
for (var i = 0; i<temp1.length; i++){
var count = 0;
if(!arr.length){arr.push(temp1[i])};
for(var x = 0; x<arr.length; x++){
if(temp1[i].address === arr[x].address){
count++;
if(temp1[i].name.length && !arr[x].name.length){arr[x] = temp1[i];} // Choose the new object if the old one has no name field
}
if((x === arr.length -1) && count === 0){
arr.push(temp1[i])
}
}
}
我在这里有一个额外的要求 - 如果arr
中的对象有一个空白字符串作为其名称字段,temp1
对象做,我想要存储而是temp1
对象。
我目前的方法需要30秒才能在Chrome中运行,这并不理想。
编辑:为了澄清,我问Javascript中是否有更有效的方法来查找数组中的唯一对象。上面的一种方法是创建一个新数组,对原始数据进行迭代,并为每个循环遍历新数组中的所有内容以检查重复项。我想知道什么比这更有效。
答案 0 :(得分:1)
这是另一种可能性
var tmp = {};
temp1.forEach(function(item) {
var key = item.address;
add = tmp[key] = tmp[key] || item;
add.name = add.name || item.name;
});
var addr = Object.keys(tmp).map(function(t) { return tmp[t] });
警告:ie9或更高版本 - 或者对于较小的浏览器使用以下polyfill
map
的 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
forEach
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
Object.keys
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
考虑@ dev-null
的评论var tmp = {}, item, key, add, i, l = temp1.length, addr;
for(i = 0; i < l; i++) {
item = temp1[i];
key = item.address;
add = tmp[key] = tmp[key] || item;
add.name = add.name || item.name;
};
addr = new Array(Object.keys(tmp).length);
i = 0;
for(key in tmp) {
addr[i++] = tmp[key];
}
这平均速度是我第一次测试的两倍(尽管在Firefox中)
比OP的原始脚本快64倍
编辑:这是最快的(在Firefox中)
var tmp = {}, item, key, add, i, l = temp1.length, addr;
for(i = 0; i < l; i++) {
item = temp1[i];
key = item.address;
add = tmp[key] = tmp[key] || item;
add.name = add.name || item.name;
};
addr = Object.keys(tmp).map(function(t) { return tmp[t] });
答案 1 :(得分:0)
var seen = {},
unique = arr.filter(function(item) {
var address = item.address;
return seen.hasOwnProperty(address ) ? false : (seen[address] = true);
});
以同样的方式,您可以添加部件来存储temp1 thingy等。
答案 2 :(得分:0)
我会使用temp对象来存储address-&gt;名称对:
var tmp = {};
for ( var i = 0; i < temp1.length; i++ ) {
var obj = temp1[i];
if ( !tmp[obj.address] ) {
tmp[obj.address] = obj.name;
}
}
这会给你一个像这样的对象:
{
"bar@moo.com": "Foo",
"mail@example.com": "John Doe",
....
}
如果你想将它翻转回一个数组,你可能想要将完整的对象存储在tmp中:
var tmp = {};
for ( var i = 0; i < temp1.length; i++ ) {
var obj = temp1[i];
if ( !tmp[obj.address] || !tmp[obj.address].name ) {
tmp[obj.address] = obj;
}
}
这将产生这样的对象:
{
"foo@bar.com": {
"name": "John Doe",
"address": "foo@bar.com"
},
...
}
从对象回到数组非常简单:
var arr = [], i = 0;
for ( var prop in tmp ) {
arr[i++] = tmp[prop];
};
如果使用new Array(length)
,可以进一步优化。因此,在初始过滤器迭代中,您需要计算新的长度。
答案 3 :(得分:0)
不是为循环中的每个新键检查arr
,而是创建一个地图,然后在地图中查找。然后最后从地图创建对象。
http://jsbin.com/wunedaxabo/edit
var arr = [];
var hashMap = {};
var isEmptyName= function(hashMap, tempObject){
var name = hashMap[tempObject.address];
return name.trim().length === 0;
};
for (var i = 0; i<temp.length; i++){
var count = 0;
var tempObject = temp[i];
//if not in the hashMap or the entry has an emptyName push into the hasMap
if(!hashMap[tempObject.address] || isEmptyName(hashMap, tempObject)){
hashMap[tempObject.address] = tempObject.name;
}
}
for(var address in hashMap){
arr.push({address: hashMap[address]});
}