一个用于压平嵌套对象的衬垫

IT技术 javascript underscore.js
2021-01-21 02:56:45

我需要展平嵌套对象。需要一个衬里。不确定这个过程的正确术语是什么。我可以使用纯 Javascript 或库,我特别喜欢下划线。

我有 ...

{
  a:2,
  b: {
    c:3
  }
}

而且我要 ...

{
  a:2,
  c:3
}

我试过了 ...

var obj = {"fred":2,"jill":4,"obby":{"john":5}};
var resultObj = _.pick(obj, "fred")
alert(JSON.stringify(resultObj));

哪个有效,但我也需要它来工作......

var obj = {"fred":2,"jill":4,"obby":{"john":5}};
var resultObj = _.pick(obj, "john")
alert(JSON.stringify(resultObj));
6个回答

干得好:

Object.assign({}, ...function _flatten(o) { return [].concat(...Object.keys(o).map(k => typeof o[k] === 'object' ? _flatten(o[k]) : ({[k]: o[k]})))}(yourObject))

总结:递归地创建一个单一属性对象的数组,然后将它们全部与Object.assign.

这使用了包括Object.assign或 展开运算符在内的 ES6 特性,但应该很容易重写而不需要它们。

对于那些不关心单行疯狂​​并且希望能够实际阅读它的人(取决于您对可读性的定义):

Object.assign(
  {}, 
  ...function _flatten(o) { 
    return [].concat(...Object.keys(o)
      .map(k => 
        typeof o[k] === 'object' ?
          _flatten(o[k]) : 
          ({[k]: o[k]})
      )
    );
  }(yourObject)
)
值得注意的是,它...是 ES6,因此可能不适用于旧版浏览器和旧版 nodejs 等。
2021-04-05 02:56:45
不能正确处理空值或数组
2021-04-13 02:56:45

简化的可读示例,无依赖

/**
 * Flatten a multidimensional object
 *
 * For example:
 *   flattenObject({ a: 1, b: { c: 2 } })
 * Returns:
 *   { a: 1, c: 2}
 */
export const flattenObject = (obj) => {
  const flattened = {}

  Object.keys(obj).forEach((key) => {
    if (typeof obj[key] === 'object' && obj[key] !== null) {
      Object.assign(flattened, flattenObject(obj[key]))
    } else {
      flattened[key] = obj[key]
    }
  })

  return flattened
}

工作示例:https : //jsfiddle.net/webbertakken/jn613d8p/2/

这是一个真正的、疯狂的单行代码,它递归地平铺嵌套对象:

const flatten = (obj, roots=[], sep='.') => Object.keys(obj).reduce((memo, prop) => Object.assign({}, memo, Object.prototype.toString.call(obj[prop]) === '[object Object]' ? flatten(obj[prop], roots.concat([prop]), sep) : {[roots.concat([prop]).join(sep)]: obj[prop]}), {})

多行版本,解释:

// $roots keeps previous parent properties as they will be added as a prefix for each prop.
// $sep is just a preference if you want to seperate nested paths other than dot.
const flatten = (obj, roots = [], sep = '.') => Object
  // find props of given object
  .keys(obj)
  // return an object by iterating props
  .reduce((memo, prop) => Object.assign(
    // create a new object
    {},
    // include previously returned object
    memo,
    Object.prototype.toString.call(obj[prop]) === '[object Object]'
      // keep working if value is an object
      ? flatten(obj[prop], roots.concat([prop]), sep)
      // include current prop and value and prefix prop with the roots
      : {[roots.concat([prop]).join(sep)]: obj[prop]}
  ), {})

一个例子:

const obj = {a: 1, b: 'b', d: {dd: 'Y'}, e: {f: {g: 'g'}}}
const flat = flatten(obj)
{
  'a': 1, 
  'b': 'b', 
  'd.dd': 'Y', 
  'e.f.g': 'g'
}

单行快乐!

@JoelB 修复了错误!
2021-03-17 02:56:45
您没有sep在递归flatten调用中传递参数,因此它使用默认值 ( .)。
2021-03-18 02:56:45

它不是一个单一的班轮,但这是一个不需要 ES6 任何东西的解决方案。它使用下划线的extend方法,可以替换为 jQuery 的方法。

function flatten(obj) {
    var flattenedObj = {};
    Object.keys(obj).forEach(function(key){
        if (typeof obj[key] === 'object') {
            $.extend(flattenedObj, flatten(obj[key]));
        } else {
            flattenedObj[key] = obj[key];
        }
    });
    return flattenedObj;    
}

以下是适用于数组、原语、正则表达式、函数、任意数量的嵌套对象级别以及我可以向它们抛出的几乎所有其他内容的普通解决方案。第一个以您期望的方式覆盖属性值Object.assign

((o) => {
  return o !== Object(o) || Array.isArray(o) ? {}
    : Object.assign({}, ...function leaves(o) {
    return [].concat.apply([], Object.entries(o)
      .map(([k, v]) => {
        return (( !v || typeof v !== 'object'
            || !Object.keys(v).some(key => v.hasOwnProperty(key))
            || Array.isArray(v))
          ? {[k]: v}
          : leaves(v)
        );
      })
    );
  }(o))
})(o)

第二个将值累积到数组中。

((o) => {
  return o !== Object(o) || Array.isArray(o) ? {}
    : (function () {
      return Object.values((function leaves(o) {
        return [].concat.apply([], !o ? [] : Object.entries(o)
          .map(([k, v]) => {
            return (( !v || typeof v !== 'object'
                || !Object.keys(v).some(k => v.hasOwnProperty(k))
                || (Array.isArray(v) && !v.some(el => typeof el === 'object')))
              ? {[k]: v}
              : leaves(v)
            );
          })
        );
      }(o))).reduce((acc, cur) => {
        return ((key) => {
          acc[key] = !acc[key] ? [cur[key]]
            : new Array(...new Set(acc[key].concat([cur[key]])))
        })(Object.keys(cur)[0]) ? acc : acc
      }, {})
    })(o);
})(o)

另外请不要在生产中包含这样的代码,因为调试非常困难。