如何使用lodash递归地从JSON中删除空对象

5
var template = {
    personal: {},
    education: {},
    certificate: [{"test": "Test"}, {}, {}],
    experience: []
}

removeEmptyObj(template);

function removeEmptyObj(obj)
for (var key in obj) {
    console.log("Foor Loop" + key + " " + obj[key]);
    if (_.isObject(obj[key]) && !_.isEmpty(obj[key])) {
        console.log("Second Loop Object:::" + key + " " + obj[key]);
        removeEmptyObj(obj[key]);
    }
    if (_.isEmpty(obj[key])) {
        console.log("Delete Object:::" + key + " " + obj[key]);
        obj = _.omitBy(obj, _.isEmpty);
    }
}
console.log(obj);
return obj;
}

目前输出为:{certificate: [{"test": "Test"}, {}, {}]}

期望输出为:{certificate: [{"test": "Test"}]}

这里出了什么问题,谢谢您的帮助 :)

5个回答

5
你可以使用_.transform()函数来递归地将对象转化为一个新的对象,并在转化过程中清除空的对象和数组。 注意:为了演示,我已经添加了更多的元素到这个结构中。

var template = {
    personal: {},
    education: {},
    certificate: [{}, {"test": "Test"}, {}, {}, [{}], [{}, 1, []]],
    experience: [[1, 2, [], { 3: [] }]]
};

function clean(el) {
  function internalClean(el) {
    return _.transform(el, function(result, value, key) {
      var isCollection = _.isObject(value);
      var cleaned = isCollection ? internalClean(value) : value;

      if (isCollection && _.isEmpty(cleaned)) {
        return;
      }

      _.isArray(result) ? result.push(cleaned) : (result[key] = cleaned);
    });
  }

  return _.isObject(el) ? internalClean(el) : el;
}

console.log(clean(template));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>


这会在数组中留下空缺。例如 [{}, { test: 1 }] 变成了 [undefined, { test: 1 }] - trincot
@trincot - 感谢您的帮助。我已经重构了它,现在它将递归地清除所有内容。 - Ori Drori
当传递一个基本类型作为参数时,仍然可以进行改进以正确工作:例如 clean("abc") 目前返回一个具有三个属性的对象,而应该只返回 "abc"。 - trincot

3
您可以使用此函数,区分普通对象和数组:

// Helper function
var isEmptyObject = _.overEvery(_.isObject, _.isEmpty);
// Actual function
function removeEmptyObj(obj) {
    return  _.isArray(obj)  ? _.reject(_.map(obj, removeEmptyObj), isEmptyObject)
          : _.isObject(obj) ? _.omitBy(_.mapValues(obj, removeEmptyObj), isEmptyObject)
          : obj; 
}

// Example
var template = {
    personal: {},
    education: {},
    certificate: [{"test": "Test"}, {}, {}],
    experience: []
}

var result = removeEmptyObj(template);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>


1
不需要使用 Lodash。一个简单的筛选器就可以做到。

var template = {
    personal: {},
    education: {},
    certificate: [{"test": "Test"}, {}, {}],
    experience: []
}

template.certificate = template.certificate.filter(o => Object.keys(o).length)

console.log(template.certificate)


我需要递归。 - Divyesh Kanzariya
我不确定证书是否总是像这样为空,也许其他对象像个人、教育、证书、经验等也是空的,需要递归处理。 - Divyesh Kanzariya
啊,我明白了你现在的输出/期望的输出。 - Jeremy Thille
请查看我的输出问题,仅限于“证书”,不包括个人、教育和经验,这已根据我的要求删除。 - Divyesh Kanzariya
请查看我的输出问题,仅涉及“证书”,问题不涉及个人、教育或经验,已根据我的要求进行了删除。 - Divyesh Kanzariya

0

你尝试过 _.omit(certificate, [{}]) 吗?我从未尝试过,但是让我知道一下


你的意思是深度删除吗?因为这种方法将删除同一级别上存在的所有出现。 - drioemgaoin
如果您深入了解我的输出问题,就会发现只有“证书”而没有个人、教育和经验方面的信息,这已经根据我的要求进行了删除。 - Divyesh Kanzariya
好的,我正在尝试建立一个快速项目来帮助您。 - drioemgaoin

0
你可以尝试这种方法,它对我来说在你的示例中有效。我很确定我们可以用更好的 lodash 方法,但至少你已经解除了阻止。
deepOmit(obj) {
    function omitFromObject(obj) {
        return _.transform(obj, function(result, value, key) {
            if (_.isNull(value) || _.isUndefined(value) || _.isEmpty(value)) {
                return;
            }

            result[key] = _.isObject(value) ? omitFromObject(value) : value;
        });
    }

    return omitFromObject(obj);
}

我刚刚检查了一下,它不起作用,但感谢你的回答@drioemgaoin。 - Divyesh Kanzariya
你是否尝试过使用你提供的相同示例或更复杂的示例进行测试?你可以给我们更多的测试上下文,因为只有少数人能够使用你的示例在我们这边工作。 - drioemgaoin
我使用@OriDrori的示例来查看他的答案。 - Divyesh Kanzariya
1
好的,超级棒,他给了你一个最终的工作解决方案!干得好! - drioemgaoin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接