如何将这个嵌套对象转换为扁平对象?

时间:2015-12-29 15:21:44

标签: javascript jquery

抱歉,我不知道如何标出问题标题。如果可能,请帮助编辑。

我有一个这样的对象:

{
    a: 'jack',
    b: {
        c: 'sparrow',
        d: {
           e: 'hahaha'
        }
    }
}

我想让它看起来像:

{
    'a': 'jack',
    'b.c': 'sparrow',
    'b.d.e': 'hahaha'
}

// so that I can use it this way:
a['b.d.e']

jQuery也可以。我知道对于嵌套对象,我可以使用a.b.d.e来获取hahaha,但今天我必须使用a['b.d.e'] -_- !!! 我怎样才能做到这一点?在此先感谢:)

11 个答案:

答案 0 :(得分:18)

您可以使用递归函数来抓取对象并为您展平它。

var test = {
    a: 'jack',
    b: {
        c: 'sparrow',
        d: {
            e: 'hahaha'
        }
    }
};

function dive(currentKey, into, target) {
    for (var i in into) {
        if (into.hasOwnProperty(i)) {
            var newKey = i;
            var newVal = into[i];
            
            if (currentKey.length > 0) {
                newKey = currentKey + '.' + i;
            }
            
            if (typeof newVal === "object") {
                dive(newKey, newVal, target);
            } else {
                target[newKey] = newVal;
            }
        }
    }
}

function flatten(arr) {
    var newObj = {};
    dive("", arr, newObj);
    return newObj;
}

var flattened = JSON.stringify(flatten(test));
console.log(flattened);

答案 1 :(得分:4)

另一种递归实现。 我只想自己编写一个实现,即使当前的实现已经非常好。

递归函数检查密钥是否为'object'类型。

  • 如果它是一个对象,我们按每个对象的键进行迭代。
  • 否则,我们将其添加到结果对象中。
function flat(res, key, val, pre = '') {
  const prefix = [pre, key].filter(v => v).join('.');
  return typeof val === 'object'
    ? Object.keys(val).reduce((prev, curr) => flat(prev, curr, val[curr], prefix), res)
    : Object.assign(res, { [prefix]: val});
}
return Object.keys(input).reduce((prev, curr) => flat(prev, curr, input[curr]), {});

扁平NPM包装

或者您可以简单地使用flat npm package,这是一个众所周知的测试库。

var flatten = require('flat')
flatten(obj);

⬑我会在严肃的代码中使用它。

[额外] Neater调用上面的函数

function flatObject(input) {
  function flat(res, key, val, pre = '') {
    const prefix = [pre, key].filter(v => v).join('.');
    return typeof val === 'object'
      ? Object.keys(val).reduce((prev, curr) => flat(prev, curr, val[curr], prefix), res)
      : Object.assign(res, { [prefix]: val});
  }

  return Object.keys(input).reduce((prev, curr) => flat(prev, curr, input[curr]), {});
}

const result = flatObject(input);

[额外]演示

http://codepen.io/zurfyx/pen/VpErja?editors=1010

function flatObject(input) {
  function flat(res, key, val, pre = '') {
    const prefix = [pre, key].filter(v => v).join('.');
    return typeof val === 'object'
      ? Object.keys(val).reduce((prev, curr) => flat(prev, curr, val[curr], prefix), res)
      : Object.assign(res, { [prefix]: val});
  }

  return Object.keys(input).reduce((prev, curr) => flat(prev, curr, input[curr]), {});
}

const result = flatObject({
    a: 'jack',
    b: {
        c: 'sparrow',
        d: {
           e: 'hahaha'
        }
    }
});

document.getElementById('code').innerHTML = JSON.stringify(result, null, 2);
<pre><code id="code"></code></pre>

答案 2 :(得分:3)

递归是这种情况的最佳解决方案。

&#13;
&#13;
function flatten(input, reference, output) {
  output = output || {};
  for (var key in input) {
    var value = input[key];
    key = reference ? reference + '.' + key : key;
    if (typeof value === 'object' && value !== null) {
      flatten(value, key, output);
    } else {
      output[key] = value;
    }
  }
  return output;
}
var result = flatten({
  a: 'jack',
  b: {
    c: 'sparrow',
    d: {
      e: 'hahaha'
    }
  }
});
document.body.textContent = JSON.stringify(result);
&#13;
&#13;
&#13;

答案 3 :(得分:3)

您可以遍历对象的entries。如果value是一个对象,则递归调用该函数。使用flatMap获得扁平化的条目数组。

然后使用Object.fromEntries()从扁平化的条目数组中获取对象

const input = {
  a: 'jack',
  b: {
    c: 'sparrow',
    d: {
      e: 'hahaha'
    }
  }
}

const getEntries = (o, prefix = '') => 
  Object.entries(o).flatMap(([k, v]) => 
    Object(v) === v  ? getEntries(v, `${prefix}${k}.`) : [ [`${prefix}${k}`, v] ]
  )

console.log(
  Object.fromEntries(getEntries(input))
)

注意Object(v) === v仅针对对象返回truetypeof v === 'object'也适用于v = null

答案 4 :(得分:2)

2020

最简单的算法。甚至容易记住:)

选项1:仅使用叶子导出平面对象。即,导出的对象仅包含末尾具有原始值的路径(请参见示例)。

//recursion: walk on each route until the primitive value.
//Did we found a primitive?
//Good, then join all keys in the current path and save it on the export object.
export function flatObject(obj) {
    const flatObject = {};
    const path = []; // current path

    function dig(obj) {
        if (obj !== Object(obj))
            /*is primitive, end of path*/
            return flatObject[path.join('.')] = obj; /*<- value*/ 
    
        //no? so this is an object with keys. go deeper on each key down
        for (let key in obj) {
            path.push(key);
            dig(obj[key]);
            path.pop();
        }
    }

    dig(obj);
    return flatObject;
}

示例

let  obj = {aaa:{bbb:{c:1,d:7}}, bb:{vv:2}}
console.log(flatObject(obj))
/*
{
  "aaa.bbb.c": 1,
  "aaa.bbb.d": 7,
  "bb.vv": 2
}
*/

选项2:导出具有所有中间路径的平面对象。 有点短和简单(请参见示例)。

export function flatObject(obj) {
    const flatObject = {};
    const path = []; // current path

    function dig(obj) {
        for (let key in obj) {
            path.push(key);
            flatObject[path.join('.')] = obj[key];
            dig(obj[key])
            path.pop();
        }
    }

    dig(obj);
    return flatObject;
}

示例

let  obj = {aaa:{bbb:{c:1,d:7}}, bb:{vv:2}}
console.log(flatObject(obj))
/*{
  "aaa": {
    "bbb": {
      "c": 1,
      "d": 7
    }
  },
  "aaa.bbb": {
    "c": 1,
    "d": 7
  },
  "aaa.bbb.c": 1,
  "aaa.bbb.d": 7,
  "bb": {
    "vv": 2
  },
  "bb.vv": 2
}
*/

答案 5 :(得分:0)

具有递归函数的aproach,对对象的键的迭代以及如果值是对象的查找。如果是,请使用更新的功能拨打电话。否则将找到的值添加到结果对象。

&#13;
&#13;
function getValues(o, a) {
    Object.keys(o).forEach(function (k) {
        if (typeof o[k] === 'object') {
            getValues(o[k], [].concat(a, k));
            return;
        }
        result[[].concat(a, k).join('.')] = o[k];
    });
}

var object = { a: 'jack', b: { c: 'sparrow', d: { e: 'hahaha' } } },
    result = {};

getValues(object);
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
&#13;
&#13;
&#13;

答案 6 :(得分:0)

仅举一个示例,如何使用ES6功能实现这一目标。

const flatObject = obj => {
    const keys = Object.keys(obj)

    return keys.reduce((acc, k) => {
        const value = obj[k]

        return typeof value === 'object' ?
             {...acc, ...ObjectUtils.flatObject(value)} :
             {...acc, [k]: value}
    } , {})
}

答案 7 :(得分:0)

使用ES6的另一种方法。

const obj = {
  a: "jack",
  b: {
    c: "sparrow",
    d: {
      e: "hahaha"
    }
  }
};

function flattenObj(value, currentKey) {
  let result = {};

  Object.keys(value).forEach(key => {

    const tempKey = currentKey ? `${currentKey}.${key}` : key;

    if (typeof value[key] !== "object") {
      result[tempKey] = value[key];
    } else {
      result = { ...result, ...flattenObj(value[key], tempKey) };
    }
  });

  return result;
}

console.log(flattenObj(obj));

答案 8 :(得分:0)

var flattenObject = function(ob) {
  var toReturn = {};

  for (var i in ob) {
    if (!ob.hasOwnProperty(i)) continue;

    if ((typeof ob[i]) == 'object' && ob[i] !== null) {
      var flatObject = flattenObject(ob[i]);
      for (var x in flatObject) {
        if (!flatObject.hasOwnProperty(x)) continue;

        toReturn[i + '.' + x] = flatObject[x];
      }
    } else {
      toReturn[i] = ob[i];
    }
  }
  console.log(toReturn)
  return toReturn;
};

var ob = {
  'a': {
    'b': {
      'b2': 2
    },
    'c': {
      'c2': 2,
      'c3': 3
    }
  }
};
flattenObject(ob);

答案 9 :(得分:0)

const flatten = function(obj) {
  const result = {};

  for (let key in obj) {
    if (typeof obj[key] === 'object') {
      const childObj = flatten(obj[key]);
    
      for (let childObjKey in childObj) {
        result[`${key}.${childObjKey}`] = childObj[childObjKey];
      }
    } else {
      result[key] = obj[key];
    }
  }
  return result
}

var test = {
    a: 'jack',
    b: {
        c: 'sparrow',
        d: {
            e: 'hahaha'
        }
    }
};

console.log(flatten(test));

答案 10 :(得分:-1)

尝试一下

const result = [].concat.apply([], parentArray.map((item: any) => item.any)

相关问题