【问题标题】:Remove same Values from array of Object从对象数组中删除相同的值
【发布时间】:2020-06-27 16:35:03
【问题描述】:

我想通过比较 2 个数组从数组中删除相同的对象。

样本数据:

arr1 = [
  {id: 1, name: "a"},
  {id: 2, name: "b"},
  {id: 3, name: "c"},
  {id: 4, name: "d"},
];

arr2 = [
  {id: 1, name: "a"},
  {id: 4, name: "d"},
];

let newArray = []; // new array with with no same values it should be unique.
arr1.map((val, i)=>{
   arr2.map((val2)=>{
    if(val.id == val2.id){
       console.log('Matched At: '+ i) // do nothing
    }else{
      newArray.push(val);
    }
   })
})
console.log(newArray); // e.g: [{id: 2, name: "b"}, {id: 3, name: "c"},];

【问题讨论】:

  • 这能回答你的问题吗? Remove duplicate values from JS array
  • 如果 arr2 包含一些要合并的独特元素怎么办?例如arr2 = [ {id: 1, name: "a"}, {id: 4, name: "d"}, {id: 5, name: "x"}, ]

标签: javascript arrays json loops javascript-objects


【解决方案1】:

您可以使用filter() 方法更新您的代码,而不是使用.map() 方法,例如:

const arr1 = [
  {id: 1, name: "a"},
  {id: 2, name: "b"},
  {id: 3, name: "c"},
  {id: 4, name: "d"},
], arr2 = [
  {id: 1, name: "a"},
  {id: 4, name: "d"},
];

let newArray = []; // new array with with no same values it should be unique.
newArray = arr1.filter(function(a) {
    for(var i=0; i < arr2.length; i++){
      if(a.id == arr2[i].id) return false;
    }
    return true;
});
console.log(newArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }

【讨论】:

    【解决方案2】:
    const isInArray = (arr, id, name) => arr.reduce((result, curr) => ((curr.name === name && curr.id === id) || result), false)
    
    const newArray = arr1.reduce((result, curr) => (isInArray(arr2, curr.id, curr.name) ? result : result.concat(curr)), [])
    

    【讨论】:

      【解决方案3】:

      Array.filter 与非Array.some 结合。

      这里的诀窍也是不要some,..

      const arr1 = [
        {id: 1, name: "a"},
        {id: 2, name: "b"},
        {id: 3, name: "c"},
        {id: 4, name: "d"},
      ], arr2 = [
        {id: 1, name: "a"},
        {id: 4, name: "d"},
      ];
      
      const newArray=arr1.filter(a=>!arr2.some(s=>s.id===a.id));
      
      console.log(newArray);
      .as-console-wrapper { max-height: 100% !important; top: 0; }

      如 cmets 中所述,该问题的解释可能略有不同。如果您还想要 arr2 中的 unqiue 项目,您基本上只需执行两次并加入。 IOW:检查 arr1 中没有 arr2 的内容,然后检查 arr2 中没有 arr1 的内容。

      例如..

      const notIn=(a,b)=>a.filter(f=>!b.some(s=>f.id===s.id));
      const newArray=[...notIn(arr1, arr2), ...notIn(arr2, arr1)];
      

      更新 2: 时间复杂度,正如 qiAlex 所提到的,循环中存在循环。尽管some 会在找到匹配项时短路,但如果数据集变大,事情可能会变慢。这是SetMap 进来的。

      所以要使用Set 来解决这个问题。

      const notIn=(a,b)=>a.filter(a=>!b.has(a.id));
      const newArray=[
        ...notIn(arr1, new Set(arr2.map(m=>m.id))),
        ...notIn(arr2, new Set(arr1.map(m=>m.id)))
      ];
      

      【讨论】:

      • 如果arr2 包含一些要合并的独特元素怎么办?
      • @qiAlex 你的意思是像一个独特的合并?需要与 OP 确认该问题,对我而言,我将问题解释为返回一个不包含另一个数组的数组。
      • 起初我和你一样不理解一个问题,这是一个公平的假设,但 OP 没有明确说明。也可以将问题理解为 2 个数组,应该将其转换为一个不包括重复项的数组,但理论上 arr1arr2 都可以包含唯一项。
      • @qiAlex 你基本上可以用同样的方式做,只需做两次并加入。我会用这个信息更新答案。
      • 在我的场景中,我在 arr2 中没有唯一值,所以答案很完美。
      【解决方案4】:

      您使用Array.prototype.some 检查第一个数组中的每个元素是否其id 位于第二个数组中。如果元素不存在,则只生成它。

      const arr1 = [
        {id: 1, name: "a"},
        {id: 2, name: "b"},
        {id: 3, name: "c"},
        {id: 4, name: "d"},
      ];
      
      const arr2 = [
        {id: 1, name: "a"},
        {id: 4, name: "d"},
      ];
      
      const result = arr1.filter(x => !arr2.some(y => y.id === x.id));
      
      console.log(result);

      【讨论】:

        【解决方案5】:

        我认为一个简单的比较器可以用于获取差异然后将它们连接起来。 使用这种方法,您不需要检查哪个数组更大。

        arr1 = [  {id: 1, name: "a"},  {id: 2, name: "b"},  {id: 3, name: "c"},  {id: 4, name: "d"}];
        
        arr2 = [  {id: 1, name: "a"},  {id: 4, name: "d"},];
        
        function localComparer(b){
          return function(a){
            return b.filter(
            function(item){
              return item.id == a.id && item.name == a.name
            }).length == 0;
          }
        }
        
        var onlyInArr1 = arr1.filter(localComparer(arr2));
        var onlyInArr2 = arr2.filter(localComparer(arr1));
        
        console.log(onlyInArr1.concat(onlyInArr2));

        【讨论】:

          【解决方案6】:

          我们可以通过检查some元素是否不包含在当前数组中来过滤值:

          const result = arr1.reduce((a, c) => {
            if (!arr2.some(a2 => a2.id === c.id))
                a.push(c);
            return a;
          }, [])
          

          一个例子:

          let arr1 = [
            {id: 1, name: "a"},
            {id: 2, name: "b"},
            {id: 3, name: "c"},
            {id: 4, name: "d"},
          ];
          
          let arr2 = [
            {id: 1, name: "a"},
            {id: 4, name: "d"},
          ];
          
          const result = arr1.reduce((a, c) => {
            if (!arr2.some(a2 => a2.id === c.id))
                a.push(c);
            return a;
          }, [])
          
          console.log(result);

          【讨论】:

            【解决方案7】:

            试试这个 -

            const arr1 = [
              {id: 1, name: "a"},
              {id: 2, name: "b"},
              {id: 3, name: "c"},
              {id: 4, name: "d"},
            ];
            
            const arr2 = [
              {id: 1, name: "a"},
              {id: 4, name: "d"},
            ];
            
            const arr3 = [...arr1, ...arr2];
            const mySubArray = _.uniq(arr3, 'id');
            console.log(mySubArray);
            &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"&gt;&lt;/script&gt;

            【讨论】:

              【解决方案8】:

              每个答案都有很多循环。

              代码的复杂度我的答案是2N,

              想法是:

              1. 合并数组。

              2. 第一个循环 - 以某种方式标记重复项

              3. 第二个循环 - 过滤掉重复项

              arr1 = [
                {id: 1, name: "a"},
                {id: 2, name: "b"},
                {id: 3, name: "c"},
                {id: 4, name: "d"},
              ];
              
              arr2 = [
                {id: 1, name: "a"},
                {id: 4, name: "d"},
              ];
              
              let newArray = [...arr1, ...arr2].reduce((acc, item, index) => {
                acc.items.push(item);
              
                if (typeof acc.map[item.id] !== 'undefined') {
                  acc.items[acc.map[item.id]] = null;
                  acc.items[index] = null;
                }
                acc.map[item.id] = index;
                
                return acc
              },  {map: {}, items: []}).items.filter(item => !!item)
              
              
              console.log(newArray);

              【讨论】:

              • Complexity of the code my answer is 2N, 好点子,如果数据集变得很大,并且性能是一个问题,这样做将是一个好主意。目前在这个小数据集上,它比一个简单的过滤器慢大约 8 倍,但我认为在它变得更快之前不需要更大的数据集。出于这个原因,我正在投票赞成这个。我想如果性能真的很重要,你甚至可以通过检查长度来做到这两点...... :)
              猜你喜欢
              • 2021-10-26
              • 2021-06-07
              • 1970-01-01
              • 2020-06-12
              • 1970-01-01
              • 2016-08-22
              • 2018-12-07
              • 1970-01-01
              • 2020-01-20
              相关资源
              最近更新 更多