如何从数组中删除重复值?当数组内的对象属性未定义时,我的代码失败

Posted

技术标签:

【中文标题】如何从数组中删除重复值?当数组内的对象属性未定义时,我的代码失败【英文标题】:How to remove duplicate values from an Array? My code fails when object property inside the array is undefined 【发布时间】:2021-07-18 07:29:56 【问题描述】:

我期待一个通用的解决方案,包括作为数组元素的高阶对象。

const input1 = [1,2,4,6,'4','1',a:1,a:1]; //my code works
const input2 = [1,2,4,6,'4','1',a:undefined,b:undefined]; //my code fails.
    
function deDuplicate(arr) 
  let obj = ;
  arr.forEach(value => 
    if (!obj[JSON.stringify(value) + typeof value]) obj[JSON.stringify(value) + typeof value] = value;
  );
  return Object.values(obj);


console.log(deDuplicate(input2));

【问题讨论】:

JSON.stringify() 删除 JSON 字符串中具有 undefinedfunction 和其他无效值的键。 JSON.stringify( a:undefined ) 是“”` 我知道。如果我删除 JSON.stringify(),那么我将无法从 Array 中删除重复的对象。 如果您不关心对象中键的顺序或 null 和 undefined 被视为相同,则可以将 JSON.stringify(Object.entries(value)) 用于对象。 见这里:levelup.gitconnected.com/… 【参考方案1】:

包括 lodash https://cdnjs.com/libraries/lodash.js 或 https://www.jsdelivr.com/package/npm/lodash

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

    const input1 = [1,2,4,6,'4','1',a:1,a:1]; //my code works
    const input2 = [1,2,4,6,'4','1',a:undefined,b:undefined]; //my code fails.

    function deDuplicate(arr) 
        let res = []
        for(const el of arr) 
            const dublicateIndex = res.findIndex( (el2) => 

                // if both nulls
                if( _.isNull(el) && _.isNull(el2) ) 
                    return true
                

                // if both undefined
                if( _.isUndefined(el) && _.isUndefined(el2) ) 
                    return true
                


                // check both are string, or numbers
                if(
                    ( _.isNumber(el) || _.isString(el)) &&
                    ( _.isNumber(el2) || _.isString(el2) )
                ) 

                    return el.toString() === el2.toString()
                

                // check if one is object, other not
                if(_.isObject(el) !== _.isObject(el2)) 
                    return false
                

                // check both is object
                if(_.isObject(el) === _.isObject(el2)) 
                    return _.isEqual(el, el2)
                

                return _.isEqual(el, el2)
            )

            if(dublicateIndex === -1) 
                res.push(el)
            
        
        return res
    

    console.log(deDuplicate(input3));

input1 - [ 1, 2, 4, 6, a: 1 ]

input2 - [ 1, 2, 4, 6, a: undefined , b: undefined ]

现场示例https://jsfiddle.net/9cx4kget/

【讨论】:

你能提供一个CDN链接来在我的html中添加loadash吗? 更新了答案。示例jsfiddle.net/knrm7q2f @SupritBeck 如果您的数组中有undefinednull,此代码将失败:[1,2,4,6,true,'4','1','hello', '你好',null,undefined,a:undefined,b:a:undefined,b:a:undefined] @AlanTishin instanceof 验证 value 的原型,因此,如果 Object 是通过 Object.create(null) 创建的 - 这将返回 false,请查看我的回复,了解如何检查 value 是否为 @987654335 @【参考方案2】:

原版解决方案

const input2 = [
  1,2,4,6,
  true,
  '4','1',
  'hello','hello',
  null,
  undefined,
  a:undefined,
  b:a:undefined,b:'hello',
  b:b:'hello',a:undefined
];

const unduplicatedInput2 = new Set(input2.map(value => 
  const isString = "string" === typeof value;
  if(isString) 
    const nValue = Number(value);
    const isNumber = nValue || 0 === nValue;
    if(isNumber) 
      return nValue;
    
  
  
  return value;
));

console.log(unduplicatedInput2);

const isObject = (o) => null !== o && 'object' === typeof o;

const sortObjectKeys = (obj) => 
  const entries = Object.entries(obj);
  const sortedEntries =
    entries.sort(([a], [b]) => (a > b) - (a < b));
  
  const deepSort = sortedEntries
    .map(([key, value]) => 
      if (isObject(value)) 
        return [key, sortObjectKeys(value)];
      
      return [key, value];
    );
    
  return Object.fromEntries(deepSort);


const duplicateObjectRemoval = (array) => 
  const extractedObjects = array
    .filter(a => isObject(a));

  const arrayWithNoObjects = array
    .filter(a => !isObject(a));
    
  const replacer = (key, value) =>
    'undefined' === typeof value ? null : value;
    
  const sortedExtractedObjects =
    extractedObjects.map(o => sortObjectKeys(o));
    
  const uniqueObjects = [...new Set(
    sortedExtractedObjects.map(o => JSON.stringify(o, replacer))
  )].map(s => JSON.parse(s));
    
  return [...arrayWithNoObjects, ...uniqueObjects];


console.log(duplicateObjectRemoval([...unduplicatedInput2]));

/*
[
  1,
  2,
  4,
  6,
  true,
  "hello",
  null,
  undefined,
  
    "a": null
  ,
  
    "b": 
      "a": null,
      "b": "hello"
    
  
]
*/

【讨论】:

你能展示一下Set 的方法是什么样的吗? 当然,您的数组中可能包含什么样的数据?对象、字符串、数字、字符串化数字,还有什么? 适用于所有数据类型。不要忘记布尔值。 @SupritBeck 只需打开控制台并点击Run code snippet 在对象情况下,此解决方案取决于对象键顺序。示例[b:b: undefined, a:undefined, b:a:undefined, b: undefined]; 将不会重复数据删除

以上是关于如何从数组中删除重复值?当数组内的对象属性未定义时,我的代码失败的主要内容,如果未能解决你的问题,请参考以下文章

从数组列表中删除重复项

使用值将数组中对象的属性合并在一起并删除重复项

如何从 jquery 对象映射中过滤唯一的数据属性值

根据自定义对象属性从数组列表中删除元素

按属性值从数组中删除项目

无法在 Vue.js 中设置未定义的属性“产品”[重复]