如何使用lodash从对象中删除空值

11

我有一个带有几个属性的对象,我想使用lodash删除空的对象/嵌套对象。最好的方法是什么?

Let template = {
      node: "test",
      representation: {
        range: { }
      },
      transmit: {
        timeMs: 0
      }
    };
template = {
      node: "test",
      transmit: {
        timeMs: 0
      }
    };

我尝试过类似的方法,但我迷失了方向。

Utils.removeEmptyObjects = function(obj) {
  return _.transform(obj, function(o, v, k) {
    if (typeof v === 'object') {
      o[k] = _.removeEmptyObjects(v);
    } else if (!_.isEmpty(v)) {
      o[k] = v;
    }
  });
};
_.mixin({
  'removeEmptyObjects': Utils.removeEmptyObjects
});
6个回答

18
你可以通过以下几个步骤来实现:
  1. 使用pickBy(),使用isObject()谓词来选择对象键值。

  2. 使用mapValues()来递归调用removeEmptyObjects(),注意它只会用于对象。

  3. 使用omitBy()isEmpty()谓词来删除mapValues()之后找到的所有空对象。

  4. 使用assign()进行赋值,并使用omitBy()isObject()谓词同时去除对象的所有原始值。

function removeEmptyObjects(obj) {
  return _(obj)
    .pickBy(_.isObject) // pick objects only
    .mapValues(removeEmptyObjects) // call only for object values
    .omitBy(_.isEmpty) // remove all empty objects
    .assign(_.omitBy(obj, _.isObject)) // assign back primitive values
    .value();
}

function removeEmptyObjects(obj) {
  return _(obj)
    .pickBy(_.isObject)
    .mapValues(removeEmptyObjects)
    .omitBy(_.isEmpty)
    .assign(_.omitBy(obj, _.isObject))
    .value();
}

_.mixin({
  removeEmptyObjects: removeEmptyObjects
});

var template = {
  node: "test",
  representation: {
    range: {}
  },
  transmit: {
    timeMs: 0
  }
};

var result = _.removeEmptyObjects(template);

document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
<script src="https://cdn.jsdelivr.net/lodash/4.13.1/lodash.min.js"></script>


它无法处理对象数组。你能否修改http://jsfiddle.net/alpeshprajapati/fy3uLpw5/中的代码?它将返回对象数组而不是对象的数组。 - Alpesh Prajapati
如果这是一个对象数组,那么请使用 lodash#map 和本函数一起使用。例如: var result = _.map(array, removeEmptyObjects); - ryeballar
我不理解这个,请你修改 jsfiddle 吗? - Alpesh Prajapati
我的 obj 包含嵌套的对象数组,例如 [and] 键。您可以在控制台中检查 'result',其中包含规则下 'and' 键的对象。 - Alpesh Prajapati
1
这里可能不够优雅,但它应该可以解决你的问题。http://jsfiddle.net/ryeballar/n0afoxdu/ - ryeballar

8
从没有嵌套对象的对象中删除未定义、null和空字符串。
_.omitBy(object, (v) => _.isUndefined(v) || _.isNull(v) || v === '');

对于嵌套对象,您可以创建一个递归函数来执行此操作。 它将移除任何级别的空对象、空数组、null、undefined和空字符串...
removeEmpty(obj) {
        let finalObj = {};
        Object.keys(obj).forEach((key) => {
            if (obj[key] && typeof obj[key] === 'object') {
                const nestedObj = removeEmpty(obj[key]);
                if (Object.keys(nestedObj).length) {
                    finalObj[key] = nestedObj;
                }
            } else if (obj[key] !== '' && obj[key] !== undefined && obj[key] !== null) {
                finalObj[key] = obj[key];
            }
        });
        return finalObj;
    }



更新于2022年11月4日

根据@RahulSoni的评论,我刚刚修复了将数组转换为对象的问题。现在应该已经全部处理完毕了。如果您有其他意见,请告知我。

removeEmpty(obj) {
    const finalObj = {};
    Object.keys(obj).forEach((key) => {
      if (obj[key] && typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
        const nestedObj = this.removeEmpty(obj[key]);
        if (Object.keys(nestedObj).length) {
          finalObj[key] = nestedObj;
        }
      } else if (Array.isArray(obj[key])) {
        if (obj[key].length) {
          obj[key].forEach((x) => {
            const nestedObj = this.removeEmpty(x);
            if (Object.keys(nestedObj).length) {
              finalObj[key] = finalObj[key] ? [...finalObj[key], nestedObj] : [nestedObj];
            }
          });
        }
      } else if (obj[key] !== '' && obj[key] !== undefined && obj[key] !== null) {
        finalObj[key] = obj[key];
      }
    });
    return finalObj;
  }

示例:

   const obj = {
            a: '',
            aa: null,
            aaa: undefined,
            aaaa: 'aaaa',
            aaaaa: 0,
            aaaaaa: 1,
            aaaaaaa: 2,
            aaaaaaaa: true,
            aaaaaaaaa: false,
            emptyObj: {},
            emptyArray: [],
            array: [
                {
                    a: '',
                    aa: null,
                    aaa: undefined,
                    aaaa: 'aaaa',
                    aaaaa: 0,
                    aaaaaa: 1,
                    aaaaaaa: 2,
                    aaaaaaaa: true,
                    aaaaaaaaa: false,
                    emptyObj: {},
                    emptyArray: [],
                    obj: {
                        a: '',
                        aa: null,
                        aaa: undefined,
                        aaaa: 'aaaa',
                        aaaaa: 0,
                        aaaaaa: 1,
                        aaaaaaa: 2,
                        aaaaaaaa: true,
                        aaaaaaaaa: false,
                        emptyObj: {},
                        emptyArray: [],
                    },
                },
                {
                    a: '',
                    aa: null,
                    aaa: undefined,
                    aaaa: 'aaaa',
                    aaaaa: 0,
                    aaaaaa: 1,
                    aaaaaaa: 2,
                    aaaaaaaa: true,
                    aaaaaaaaa: false,
                    emptyObj: {},
                    emptyArray: [],
                    obj: {
                        a: '',
                        aa: null,
                        aaa: undefined,
                        aaaa: 'aaaa',
                        aaaaa: 0,
                        aaaaaa: 1,
                        aaaaaaa: 2,
                        aaaaaaaa: true,
                        aaaaaaaaa: false,
                        emptyObj: {},
                        emptyArray: [],
                    },
                },
            ],
            b: {
                a: '',
                aa: null,
                aaa: undefined,
                aaaa: 'aaaa',
                aaaaa: 0,
                aaaaaa: 1,
                aaaaaaa: 2,
                aaaaaaaa: true,
                aaaaaaaaa: false,
                emptyObj: {},
                emptyArray: [],
                c: {
                    a: '',
                    aa: null,
                    aaa: undefined,
                    aaaa: 'aaaa',
                    aaaaa: 0,
                    aaaaaa: 1,
                    aaaaaaa: 2,
                    aaaaaaaa: true,
                    aaaaaaaaa: false,
                    emptyObj: {},
                    emptyArray: [],
                },
            },
        };

        const finalObj = removeEmpty(obj);
        console.log('finalObj After remove', finalObj);

1
我已经更新了关于嵌套对象的答案,但没有使用lodash。 - Amr Omar
1
@AmrOmar 处理嵌套但将数组转换为对象。 - Rahul Soni
@RahulSoni,请给我们提供一个示例,因为我无法复现那个问题。 - Amr Omar
@AmrOmar,你自己的示例就可以做到这一点,尝试执行它!键“array”将变成一个对象。 - Rahul Soni
@RahulSoni,我已经修复了。请检查并告诉我是否有其他意见。谢谢。 - Amr Omar
显示剩余2条评论

0

这个(TypeScript)也适用于数组,并支持树摇动:

import flow from "lodash/fp/flow";
import pickBy from "lodash/fp/pickBy";
import mapValues from "lodash/fp/mapValues";
import map from "lodash/fp/map";
import assign from "lodash/fp/assign";
import { default as fpOmitBy } from "lodash/fp/omitBy";
import { default as fpFilter } from "lodash/fp/filter";
import { isArray, isEmpty, isObject, omitBy } from "lodash-es";

export const compact = (obj) => !isObject(obj) ? obj : isArray(obj) ? compactArray(obj) : compactObject(obj);

const compactArray = (arr) => flow(
  map(compact),
  fpFilter(x => !isEmpty(x) || !isObject(x)),
)(arr)

const compactObject = (obj) =>  flow(
  pickBy(isObject),
  mapValues(compact), 
  fpOmitBy(isEmpty),
  assign(omitBy(obj, isObject)),
)(obj);

0
这是Amr的函数的修改版本,解决了我遇到的一个问题,即当输入像这样时它会给出错误的结果:
const data = {
                    key1: 'value1',
                    topLevelKey1: {
                    key2: {}
                    },
                    key3: 'value3',
                    updates: [
                    { toDeleteKey: {}, fullKey: 'has a value' },
                    { toDeleteKey2: {}, fullKey2: 'has a value',
                    media: [
                        "https://thisisalink.com",
                        "https://thisisanotherlink.com",
                      ]},
                    ],
                };

它会将媒体中的字符串像对象一样处理,并将它们拆分出来,如下所示:
"media":[{"0":"h","1":"t","2":"t","3":"p","4":"s"...

function removeEmpty(obj: Record<string, any>): Record<string, any> {
    const finalObj: Record<string, any> = {};
    Object.keys(obj).forEach((key) => {
      if (obj[key] && typeof obj[key] === 'object' && !Array.isArray(obj[key])) {
        const nestedObj = removeEmpty(obj[key]);
        if (Object.keys(nestedObj).length) {
          finalObj[key] = nestedObj;
        }
      } else if (Array.isArray(obj[key])) {
        if (obj[key].length) {
          finalObj[key] = obj[key].map((x) => {
            if (typeof x === 'object' && !Array.isArray(x)) {
              return removeEmpty(x);
            } else {
              return x;
            }
          });
        }
      } else if (obj[key] !== '' && obj[key] !== undefined && obj[key] !== null) {
        finalObj[key] = obj[key];
      }
    });
    return finalObj;
  }

-1
我更新这篇文章是为了那些未来搜索解决方案的人。 lodash 提供了一种更简单的方法来解决这个问题。
使用 lodash 的 _.compact(arrayName) 可以从数组中删除所有空/未定义/空值。

-3
你可以使用_.pick来选择你想要的属性,如下:
var desiredTemplate = _.pick(template, ['node','transmit']); 

否则,据我所知,lodash没有内置可以递归地从对象中删除空对象或数组的功能。

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