【问题标题】:Filter from two array of objects and then merge them从两个对象数组中过滤,然后合并它们
【发布时间】:2019-08-29 10:12:08
【问题描述】:

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

数组1:

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

数组2:

[
  {
    "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 实现这一目标的最佳方法是什么?

【问题讨论】:

  • 但是你的 filter 函数已经在他的核心中循环了。为什么不将filter 替换为循环,它会过滤并将数据添加到array1
  • 有没有可能,具有相同电子邮件/电话的记录有不同的名称?预期的结果数组可以用于完整的问题陈述。
  • @YevgenGorbunkov 是的,记录也可以有不同的名称
  • 数据从何而来?如果它来自数据库连接,那么优化查询而不是通过代码过滤/合并可能是有意义的,因为您不会摆脱公共循环。
  • 一万条记录和重复搜索,你需要重新排列你的数据。考虑创建按电话或电子邮件分组的数据的索引版本,这将使这些类型的操作快速而直接。

标签: javascript arrays ecmascript-6


【解决方案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)

【讨论】:

  • 但是“Name3”呢?看起来此用户已在您的合并过程中被删除。
【解决方案2】:

使用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); 

【讨论】:

    【解决方案3】:

    使用地图并查找。但是,这只会将数组 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”对于避免迭代第二个数组很有用。

    【讨论】:

      【解决方案4】:

      这是一种两阶段方法,适用于要合并的任意数量的数组。

      首先,所有条目都放在一个对象 (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)
      }

      【讨论】:

        猜你喜欢
        • 2023-03-18
        • 2016-09-23
        • 1970-01-01
        • 2020-07-03
        • 2019-07-09
        • 2016-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多