删除嵌套数组中具有键值的对象

Posted

技术标签:

【中文标题】删除嵌套数组中具有键值的对象【英文标题】:delete an object in a nested array which has key value 【发布时间】:2019-03-29 15:01:15 【问题描述】:

我想删除每个部分下唯一的低级对象(例如在下面的代码中,在个人数据下有两个对象...我想删除一个对象,其中操作:旧)在每个部分下,其中“操作”: “旧”

我在我的项目中使用 lodash

[
  
    "clientDetails": 
      "personalData": [
        
          "action": "NEW",
          "id": "12345"
        ,
        
          "action": "OLD",
          "id": "12445"
        
      ]
    ,
    "clientAddress": 
      "primaryAddress": [
        
          "action": "OLD",
          "id": "12345"
        ,
        
          "action": "NEW",
          "id": "12445"
        
      ],
      "secondaryAddress": [
        
          "action": "NEW",
          "id": "12345"
        ,
        
          "action": "OLD",
          "id": "12445"
        
      ]
    
  ,
  
    "clientDemise": 
      "deathDetails": [
        
          "action": "NEW",
          "id": "12345"
        ,
        
          "action": "OLD",
          "id": "12445"
        
      ]
    ,
    "clientMarital": 
      "divorceInformation": [
        
          "action": "OLD",
          "id": "12345"
        ,
        
          "action": "NEW",
          "id": "12445"
        
      ],
      "marraigeInformation": [
        
          "action": "NEW",
          "id": "12345"
        ,
        
          "action": "OLD",
          "id": "12445"
        
      ]
    
  
]

抱歉发错了,这是我第一次发帖

【问题讨论】:

这个的o/p应该是什么? 【参考方案1】:

如果您的数据结构相当一致(即类似于您在问题中包含的内容),您可以执行以下操作:

const mapObj = (f, obj) => 
    return Object.keys(obj).reduce((acc, key) => 
        acc[key] = f(obj[key], key)
        return acc
    , )


const filterData = data => 
    // the data itself is an array, so iterate over each item in the array
    return data.map(x1 => 
        // x1 is an object, so need to iterate over each item in the object
        return mapObj(x2 => 
            // x2 is an object, so need to iterate over each item in the object
            return mapObj(x3 => 
                // x3 is an array of objects. each item in the array has an action key which could equal "NEW" or "OLD". get rido of the items with action === "OLD"
                return x3.filter(x4 => x4.action !== "OLD")
            , x2)
        , x1)
    )


const data = [
  
    "clientDetails": 
      "personalData": [
        
          "action": "NEW",
          "id": "12345"
        ,
        
          "action": "OLD",
          "id": "12445"
        
      ]
    ,
    "clientAddress": 
      "primaryAddress": [
        
          "action": "OLD",
          "id": "12345"
        ,
        
          "action": "NEW",
          "id": "12445"
        
      ],
      "secondaryAddress": [
        
          "action": "NEW",
          "id": "12345"
        ,
        
          "action": "OLD",
          "id": "12445"
        
      ]
    
  ,
  
    "clientDemise": 
      "deathDetails": [
        
          "action": "NEW",
          "id": "12345"
        ,
        
          "action": "OLD",
          "id": "12445"
        
      ]
    ,
    "clientMarital": 
      "divorceInformation": [
        
          "action": "OLD",
          "id": "12345"
        ,
        
          "action": "NEW",
          "id": "12445"
        
      ],
      "marraigeInformation": [
        
          "action": "NEW",
          "id": "12345"
        ,
        
          "action": "OLD",
          "id": "12445"
        
      ]
    
  
]

const result = filterData(data)
console.log(result)

如果您想要一个更通用的解决方案,该解决方案可以获取任何结构的数据,并且只需使用等于“OLD”的操作删除所有对象:

const reduceObj = (f, initial, obj) => 
    return Object.keys(obj).reduce((acc, key) => 
        return f(acc, obj[key], key)
    , initial)


const isObject = x => x !== null && typeof x === 'object'

const removeAllOld = data => 
    if(Array.isArray(data)) 
        return data.reduce((acc, value) => 
            // don't include the item if it has a key named 'action' that is equal to 'OLD'
            if(value.action && value.action === 'OLD') return acc

            acc.push(removeAllOld(value))
            return acc
        , [])
    
    else if(isObject(data)) 
        return reduceObj((acc, value, key) => 
            // don't include the item if it has a key named 'action' that is equal to 'OLD'
            if(value.action && value.action === 'OLD') return acc

            acc[key] = removeAllOld(value)
            return acc
        , , data)
    
    else 
        return data
    


const data = [
  
    "clientDetails": 
      "personalData": [
        
          "action": "NEW",
          "id": "12345"
        ,
        
          "action": "OLD",
          "id": "12445"
        
      ]
    ,
    "clientAddress": 
      "primaryAddress": [
        
          "action": "OLD",
          "id": "12345"
        ,
        
          "action": "NEW",
          "id": "12445"
        
      ],
      "secondaryAddress": [
        
          "action": "NEW",
          "id": "12345"
        ,
        
          "action": "OLD",
          "id": "12445"
        
      ]
    
  ,
  
    "clientDemise": 
      "deathDetails": [
        
          "action": "NEW",
          "id": "12345"
        ,
        
          "action": "OLD",
          "id": "12445"
        
      ]
    ,
    "clientMarital": 
      "divorceInformation": [
        
          "action": "OLD",
          "id": "12345"
        ,
        
          "action": "NEW",
          "id": "12445"
        
      ],
      "marraigeInformation": [
        
          "action": "NEW",
          "id": "12345"
        ,
        
          "action": "OLD",
          "id": "12445"
        
      ]
    
  
]

console.log(removeAllOld(data))

【讨论】:

【参考方案2】:

您可以使用 javascript 过滤器。不使用 lodash 来减少你的 bundle 大小。

// it's upto you, you can use new Array() as well and insert if(ktm.action==='NEW')
clients = clients.filter(function(itm) 
  Object.keys(itm).forEach(function(Okey, Ovalue) 
    Object.keys(itm[Okey]).forEach(function(inkey, invalue) 
      itm[Okey][inkey].filter(function(ktm) 
        if (ktm.action === 'OLD') 
          // perform your logic, either you can insert into new Array() or 
          // delete that object and return clients
        
      );
    );
  );
);

【讨论】:

【参考方案3】:

考虑到这一点,只需几行就可以实现这一点

input = your input

这种和平的代码将完成工作

for (var i of input) 
  for (var j in i) 
   var ob = i[j];
   for (var k in ob) 
     var index = _.findIndex(ob[k], 'action': 'OLD');
     if (index > -1) 
       ob[k].splice(index, 1);
     
   
 

【讨论】:

这是一个不错的简短解决方案。您可以删除 toRemove 变量,顺便说一句。此外,您可以将其转换为代码 sn-p,并将 lodash 作为外部库包含在内。 非常感谢您的建议,我删除了不必要的变量,如果需要,将创建代码 sn-p。 但这不能用于删除不需要的数据的多个条目(如果需要) 你的代码可以工作...谢谢.. 但是如果没有主地址@ShyamTayal,它会抛出错误 ob[k].splice is not a function 例如在上面的代码中 我认为最后一级字段是一个数组,如果不是这样,请在第三个循环中添加类型检查以避免任何错误。希望对你有帮助【参考方案4】:

你可以像这样做一个深拷贝:

    const array = [
      
        "clientDetails": 
          "personalData": [
            
              "action": "NEW",
              "id": "12345"
            ,
            
              "action": "OLD",
              "id": "12445"
            
          ]
        ,
        "clientAddress": 
          "primaryAddress": [
            
              "action": "OLD",
              "id": "12345"
            ,
            
              "action": "NEW",
              "id": "12445"
            
          ],
          "secondaryAddress": [
            
              "action": "NEW",
              "id": "12345"
            ,
            
              "action": "OLD",
              "id": "12445"
            
          ]
        
      ,
      
        "clientDemise": 
          "deathDetails": [
            
              "action": "NEW",
              "id": "12345"
            ,
            
              "action": "OLD",
              "id": "12445"
            
          ]
        ,
        "clientMarital": 
          "divorceInformation": [
            
              "action": "OLD",
              "id": "12345"
            ,
            
              "action": "NEW",
              "id": "12445"
            
          ],
          "marraigeInformation": [
            
              "action": "NEW",
              "id": "12345"
            ,
            
              "action": "OLD",
              "id": "12445"
            
          ]
        
      
    ]    
    function removeOldAction(a) 
    if (a instanceof Array) 
        let copiee = [];
        for (let item in a) 
            const propValue = removeOldAction(a[item]);
            if(propValue) 
                copiee.push(propValue);
            
        
        return copiee;
    
    if (a instanceof Object) 
        if (a['action'] === 'OLD')  
            return; 
        
        let copiee = ;
        for (let key in a) 
            copiee[key] = removeOldAction(a[key]);
        
        return copiee;
     
    return a;


    console.log(removeOldAction(array));

【讨论】:

【参考方案5】:

你可以通过类似这样的方式来实现这一点,而无需 lodash:

var data = [ "clientDetails":  "personalData": [ "action": "NEW", "id": "12345" ,  "action": "OLD", "id": "12445"  ] , "clientAddress":  "primaryAddress": [ "action": "OLD", "id": "12345" ,  "action": "NEW", "id": "12445"  ], "secondaryAddress": [ "action": "NEW", "id": "12345" ,  "action": "OLD", "id": "12445"  ]  ,  "clientDemise":  "deathDetails": [ "action": "NEW", "id": "12345" ,  "action": "OLD", "id": "12445"  ] , "clientMarital":  "divorceInformation": [ "action": "OLD", "id": "12345" ,  "action": "NEW", "id": "12445"  ], "marraigeInformation": [ "action": "NEW", "id": "12345" ,  "action": "OLD", "id": "12445"  ]   ]

const removeOld = (data) => data.map(x => 
   Object.entries(x).reduce((r, [k,v]) => 
      r[k] = Object.entries(v).map(([o,p]) => 
        ([o]: p.filter(n => n.action != 'OLD')))
      return r
   ,))

console.log(removeOld(data))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

使用map、Object.entries、reduce 和filter。

另一种方法是在 ES6 中使用类似于 @Vanojx1 方法的递归:

var data = [ "clientDetails":  "personalData": [ "action": "NEW", "id": "12345" ,  "action": "OLD", "id": "12445"  ] , "clientAddress":  "primaryAddress": [ "action": "OLD", "id": "12345" ,  "action": "NEW", "id": "12445"  ], "secondaryAddress": [ "action": "NEW", "id": "12345" ,  "action": "OLD", "id": "12445"  ]  ,  "clientDemise":  "deathDetails": [ "action": "NEW", "id": "12345" ,  "action": "OLD", "id": "12445"  ] , "clientMarital":  "divorceInformation": [ "action": "OLD", "id": "12345" ,  "action": "NEW", "id": "12445"  ], "marraigeInformation": [ "action": "NEW", "id": "12345" ,  "action": "OLD", "id": "12445"  ]   ]

const removeOld = (data) => 
  Array.isArray(data) ? data.filter(x => x.action != 'OLD').map(x => removeOld(x)) :
  typeof(data) == 'object' ? Object.entries(data).reduce((r, [k,v]) => (r[k] = removeOld(v), r), ) : 
  data

console.log(removeOld(data))

【讨论】:

【参考方案6】:

结构独立的解决方案检查每个对象节点中的操作

var data=[clientDetails:personalData:[action:"NEW",id:"12345",action:"OLD",id:"12445"],clientAddress:primaryAddress:[action:"OLD",id:"12345",action:"NEW",id:"12445"],secondaryAddress:[action:"NEW",id:"12345",action:"OLD",id:"12445"],clientDemise:deathDetails:[action:"NEW",id:"12345",action:"OLD",id:"12445"],clientMarital:divorceInformation:[action:"OLD",id:"12345",action:"NEW",id:"12445"],marraigeInformation:[action:"NEW",id:"12345",action:"OLD",id:"12445"]];

const reducer = (curr) => 
  if(_.isArray(curr))
    return _(curr)
      .filter(el => !('action' in el && el.action == 'OLD'))
      .map(el => reducer(el))
      .value()
  else if(_.isObject(curr)) 
    return _(curr)
      .mapValues(el => reducer(el))
      .value()
   else
    return curr;
;

console.log(reducer(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

【讨论】:

【参考方案7】:

让我们不要改变原始输入数据,使用定制器克隆它,并拒绝定制器中不需要的东西(如果它们存在),以便按预期获得更干净的克隆输出。你可以使用lodash#cloneDeepWith

_.cloneDeepWith(input, v => _.find(v, action: "OLD") ? _.reject(v, action: "OLD") : undefined);

这只是对您想要拒绝的内容进行(硬编码)的示例。但是您可以将其包装在回调中并将拒绝标准作为参数以使其动态化。

所以我们开始:

let input = ["clientDetails":"personalData":["action":"NEW","id":"12345","action":"OLD","id":"12445"],"clientAddress":"primaryAddress":["action":"OLD","id":"12345","action":"NEW","id":"12445"],"secondaryAddress":["action":"NEW","id":"12345","action":"OLD","id":"12445"],"clientDemise":"deathDetails":["action":"NEW","id":"12345","action":"OLD","id":"12445"],"clientMarital":"divorceInformation":["action":"OLD","id":"12345","action":"NEW","id":"12445"],"marraigeInformation":["action":"NEW","id":"12345","action":"OLD","id":"12445"]],
    clear = (input, rej) => (
      _.cloneDeepWith(input, v => _.find(v, rej) ? _.reject(v, rej) : undefined)
    ),
    res;
  
res = clear(input, action: "OLD"); //you can filter out action: OLD
console.log(res);

res = clear(input, action: "NEW"); //you can filter out action: NEW
console.log(res);

res = clear(input, d => d.action==="OLD"); //you can filter with custom callback with complex logic
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

【讨论】:

以上是关于删除嵌套数组中具有键值的对象的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript:检查对象数组中是不是存在重复的键值并删除所有但最近添加的具有该键值的对象

检查对象数组中是不是存在具有特定键值的对象

如何在数组中找到具有相同键值的对象?

javascript 将查询字符串数组拆分为具有键值的对象的函数

根据嵌套键值对对象数组进行排序的最快方法

如何从嵌套对象中获取具有值的所有键