从两个对象数组过滤,然后合并它们

时间:2019-08-29 10:12:08

标签: javascript arrays ecmascript-6

我的要求是从两个数组中基于PhoneEmail查找公用对象,即如果Phone为null or '',则使用电子邮件查找公用对象,反之亦然。从两个数组中找到共同点后,我要合并这两个对象,以便它们都具有相同的键/值对。我设法找到了共同点,但未能将它们合并。这是我到目前为止所做的。

Array1:

[
  {
    "Name": "Name1",
    "Phone": "",
    "Email": "name1@mail.com",
    "ID": 1
  },
  {
    "Name": "Name2",
    "Phone": "12345566",
    "Email": "name2@mail.com",
    "ID": 2
  }
]

Array2:

[
  {
    "Name": "Name1",
    "Phone": "987654321",
    "Email": "name1@mail.com"
  },
  {
    "Name": "Name2",
    "Phone": "12345566",
    "Email": "name2@mail.com"
  },
  {
    "Name": "Name3",
    "Phone": "23445677",
    "Email": ""
  }
]

这就是我设法从这两者中获得共同点的方法。

const common = array1
                  .filter(user=> 
                  array2.some(otherUser => 
                  (user.Email && (user.Email === otherUser.Email)) ||
                  (user.Phone && (user.Phone === otherUser.Phone))));

在不使用common数组的循环的情况下,如何合并这两者,因为这将花费很多时间,因为我的数组中的数据可能包含成千上万的记录? 使用ES6实现此目标的最佳方法是什么?

4 个答案:

答案 0 :(得分:1)

您的方法很明确。使用some()比较值时,只需覆盖过滤后的数组的值即可。

示例:

const arr1 = [{ "Name": "Name1", "Phone": "", "Email": "name1@mail.com", "ID": 1 },{ "Name": "Name2", "Phone": "12345566", "Email": "name2@mail.com", "ID": 2 }];
const arr2 = [{"Name": "Name1","Phone": "987654321","Email": "name1@mail.com"},{"Name": "Name2","Phone": "12345566","Email": "name2@mail.com"},{"Name": "Name3","Phone": "23445677","Email": ""}];

const arr3 = arr1.filter(i => {
    return arr2.some(v => {
        if (i.Phone === v.Phone || i.Email === v.Email) {
            !i.Phone && (i.Phone = v.Phone), !i.Email && (i.Phone = v.Email)
            return !0
        }
    })
})

console.log(arr3)

答案 1 :(得分:0)

使用for loop

const arra1 = [
  {
    Name: 'Name1',
    Phone: '',
    Email: 'name1@mail.com',
    ID: 1,
  },
  {
    Name: 'Name2',
    Phone: '12345566',
    Email: 'name2@mail.com',
    ID: 2,
  },
];


const arr2 = [
  {
    Name: 'Name1',
    Phone: '987654321',
    Email: 'name1@mail.com',
  },
  {
    Name: 'Name2',
    Phone: '12345566',
    Email: 'name2@mail.com',
  },
  {
    Name: 'Name3',
    Phone: '23445677',
    Email: '',
  },
];

const common = [];

for (let i = 0; i < arra1.length; i += 1) {
  const element = arra1[i];
  const { Phone, Email } = element;
  let searchKey = null;
  let searchValue = null;
  if (Phone) {
    searchKey = 'Phone';
    searchValue = Phone;
  } else if (Email) {
    searchKey = 'Email';
    searchValue = Email;
  }
  const index = arr2.findIndex((r) => {
    return searchKey ? r[searchKey] === searchValue : false;
  });
  if (index > -1) {
    common.push(element);
  }
}

console.log(common); 

使用filter

const arra1 = [
  {
    Name: 'Name1',
    Phone: '',
    Email: 'name1@mail.com',
    ID: 1,
  },
  {
    Name: 'Name2',
    Phone: '12345566',
    Email: 'name2@mail.com',
    ID: 2,
  },
];


const arr2 = [
  {
    Name: 'Name1',
    Phone: '987654321',
    Email: 'name1@mail.com',
  },
  {
    Name: 'Name2',
    Phone: '12345566',
    Email: 'name2@mail.com',
  },
  {
    Name: 'Name3',
    Phone: '23445677',
    Email: '',
  },
];

const common = arra1.filter((f) => {
  const { Phone, Email } = f;
  let searchKey = null;
  let searchValue = null;
  if (Phone) {
    searchKey = 'Phone';
    searchValue = Phone;
  } else if (Email) {
    searchKey = 'Email';
    searchValue = Email;
  }
  const index = arr2.findIndex((r) => {
    return searchKey ? r[searchKey] === searchValue : false;
  });
  return !!(index > -1);
});

console.log(common); 

答案 2 :(得分:0)

使用地图查找。但是,这只会从数组1到数组2中找到丢失的字段。如果需要完全连接,则必须执行两次,然后使用Object.assign()。

const common = array1.map(user => {
    if ((user.Email && user.Phone) || (!user.Email && !user.Phone)) {
        return user;
    }
    else if (!user.Phone) {
        const match = array2.find(otherUser => {
            return otherUser.Email === user.Email;
        });
        user.Phone = match.Phone;
    }
    else if (!user.Email) {
        const match = array2.find(otherUser => {
            return otherUser.Phone === user.Phone;
        });
        user.Email = match.Email;
    }
    return user;
})

如果两个字段均已填充或缺失,则第一个“ if”可用于避免迭代第二个数组。

答案 3 :(得分:0)

这是一种两阶段方法,可与任意数量的要合并的数组一起使用。

首先,将所有条目放到一个对象(merged)中,该对象具有电子邮件和电话号码的组合。作为关键。然后,我通过将带有部分密钥的条目与具有完整密钥标识的那些条目组合在一起,来进一步巩固它。

var arr1= [
  { "Name": "Name1", "Phone": "", "Email": "name1@mail.com", "ID": 1 },
  { "Name": "Name2", "Phone": "12345566", "Email": "name2@mail.com", "ID": 2 },
  { "Name": "Name3", "Phone": "23445677", "Email": "name3@mail.com" } ],
     arr2=[
  { "Name": "Name1", "Phone": "987654321", "Email": "name1@mail.com" },
  { "Name": "Name2", "Phone": "12345566", "Email": "name2@mail.com" },
  { "Name": "Name3", "Phone": "23445677", "Email": "" , "ID": 3 }
];

console.log(merge(arr1,arr2))

function merge(arr) {
  var merged={};
  for (var i=1;i<arguments.length;i++) arr=arr.concat(arguments[i]);
  arr.forEach(function(o){ // first round of merging ...
    var k=(o.Email||'')+'|'+(o.Phone||'');
    if (!merged[k]) merged[k]=o;
    else for (p in o) merged[k][p]=o[p];
  });
  var keys=Object.keys(merged);
  keys.forEach((k,i)=>{
    var l=k.length,p,o=merged[k];
    // now look for partial matches (only phone no. given)
    if (k[0]=='|'){ keys.forEach((kk,j)=>{
      if(j!=i && kk.substr(kk.length-l)==k) {
        for (p in o) if(o[p]) merged[kk][p]=o[p];
        delete merged[k];
      }
      })
    }
    else if (k[l-1]=='|'){ keys.forEach((kk,j)=>{
    // partial matches (only email given)
      if(j!=i && kk.substr(0,l)==k) {
        for (p in o) if(o[p]) merged[kk][p]=o[p];
        delete merged[k];
      }
      })
    }
  })
  return Object.values(merged)
}