Javascript 将 JS 对象(键和值)展平为单个深度数组的最佳方法
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44134212/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Best way to flatten JS object (keys and values) to a single depth array
提问by ddomingo
I have written this small function to get all keys and values of an object and store them into an array. The object might contain arrays as values...
我编写了这个小函数来获取对象的所有键和值并将它们存储到数组中。该对象可能包含数组作为值...
Object { 0: [1,2,3,4] }to [0,1,2,3,4]converting all elements to integers
Object { 0: [1,2,3,4] }到[0,1,2,3,4]转换的所有元素为整数
I wonder whether there is a faster/cleaner way to do so:
我想知道是否有更快/更清洁的方法来做到这一点:
function flattenObject(obj) {
// Returns array with all keys and values of an object
var array = [];
$.each(obj, function (key, value) {
array.push(key);
if ($.isArray(value)) {
$.each(value, function (index, element) {
array.push(element);
});
}
else {
array.push(value);
}
});
return array
}
采纳答案by Nina Scholz
You could just concat all keys and values. (It does not solve the type casting to number for keys.)
您可以连接所有键和值。(它不能解决键的类型转换为数字的问题。)
var object = { 0: [1, 2, 3, 4] },
result = Object.keys(object).reduce(function (r, k) {
return r.concat(k, object[k]);
}, []);
console.log(result);
回答by Muthukrishnan
I wanted to flatten my deep object to one level depth. None of the above solutions worked for me.
我想将我的深层物体展平到一层深度。以上解决方案都不适合我。
My input:
我的输入:
{
"user": {
"key_value_map": {
"CreatedDate": "123424",
"Department": {
"Name": "XYZ"
}
}
}
}
Expected output:
预期输出:
{
"user.key_value_map.CreatedDate": "123424",
"user.key_value_map.Department.Name": "XYZ"
}
Code that worked for me:
对我有用的代码:
function flattenObject(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];
}
}
return toReturn;
}
回答by Tanvi Bhatia
Flattening Object can be done using recursion as below :
扁平对象可以使用递归来完成,如下所示:
Sample Input
样本输入
let obj = {
name: "test",
address: {
personal: "abc",
office: {
building : 'random'
street : 'some street',
}
}
}
Expected Output
预期产出
{
name : "test",
address_personal: "abc"
address_office_building: "random"
address_office_street: "some street"
}
My Solution
我的解决方案
function flattenObj(obj, parent, res = {}){
for(let key in obj){
let propName = parent ? parent + '_' + key : key;
if(typeof obj[key] == 'object'){
flattenObj(obj[key], propName, res);
} else {
res[propName] = obj[key];
}
}
return res;
}
Hope it helps
希望能帮助到你
回答by Tofandel
This answer is an improvement over @Muthukrishnan 's answer
这个答案是对@Muthukrishnan 的答案的改进
If you want to flatten an object deeply outputting the values into a one level deep object keyed with the path of the value in the previous object
如果要将对象深度展平,则将值输出到以前一个对象中值的路径为键的一级深度对象中
(eg: { foo: { bar: 'baz'} }=> { 'foo.bar': 'baz' })
(例如:{ foo: { bar: 'baz'} }=> { 'foo.bar': 'baz' })
Here is how you can effectively do it:
以下是如何有效地做到这一点:
/**
* @param Object ob The object to flatten
* @param String prefix (Optional) The prefix to add before each key, also used for recursion
**/
function flattenObject(ob, prefix) {
const toReturn = {};
prefix = prefix ? prefix + '.' : '';
for (let i in ob) {
if (!ob.hasOwnProperty(i)) continue;
if (typeof ob[i] === 'object' && ob[i] !== null) {
// Recursion on deeper objects
Object.assign(toReturn, flattenObject(ob[i], prefix + i));
} else {
toReturn[prefix + i] = ob[i];
}
}
return toReturn;
}
/**
* Bonus function to unflatten an object
*
* @param Object ob The object to unflatten
*/
function unflattenObject(ob) {
const result = {};
for (let i in ob) {
if (ob.hasOwnProperty(i)) {
const keys = i.split(/(?<!\.|^)\.(?!\.+|$)/); // Just a complicated regex to only match a single dot in the middle of the string
keys.reduce((r, e, j) => {
return r[e] || (r[e] = isNaN(Number(keys[j + 1])) ? (keys.length - 1 === j ? ob[i] : {}) : [])
}, result);
}
}
return result;
};
// TESTS
const obj = {
value: {
foo: {
bar: 'yes',
so: {
freakin: {
nested: 'Wow',
}
}
},
},
// Some edge cases to test
test: [true, false, [null, undefined, 1]],
// Be careful with object having dots in the keys
'I.like.dots.in.object.keys...': "... Please don't override me",
I: {
like: {
dots: { in: {
object: {
'keys...': "You've been overwritten"
}
}
}
}
}
};
let flat = flattenObject(obj);
console.log(flat, unflattenObject(flat));
There is an obvious problem that you could encounter with flattening this way if your object contains keys with dots, this is documented in the fiddle
如果您的对象包含带点的键,您可能会遇到一个明显的问题,以这种方式展平,这在小提琴中记录
回答by husayt
I needed something really simple and here is a one-liner I came up with:
我需要一些非常简单的东西,这是我想出的一个单线:
function flatten(obj){
return Object.values(obj).flat()
}
Obviously, this is subject to your browser/JS env supporting this syntax. Here is a working example.
显然,这取决于您的浏览器/JS 环境是否支持这种语法。这是一个工作示例。
const flatten=(obj)=>Object.values(obj).flat()
const x={x:[1,2,3],y:[4,5,6,7]}
console.log(flatten(x))
回答by husayt
Generate an array of tuples (two-element arrays) of keys and values (which might themselves be arrays), then deep-flatten it.
生成键和值(它们本身可能是数组)的元组数组(二元素数组),然后对其进行深度扁平化。
function flattenObject(obj) {
return flatten(Object.keys(obj).map(k => [toNumber(k), obj[k]]));
}
// Substitute your own favorite flattening algorithm.
const flatten = a => Array.isArray(a) ? [].concat(...a.map(flatten)) : a;
// Convert to number, if you can.
const toNumber = n => isNaN(+n) ? n : +n;
console.log(flattenObject({a: [1, 2], b: 3, 0: [1, 2, 3, 4, 5]}));
回答by RahulB
You can skip the inner loop if you have to push contents of an array to another array. See if this helps --
如果必须将数组的内容推送到另一个数组,则可以跳过内部循环。看看这是否有帮助——
function flattenObject(obj) {
// Returns array with all keys and values of an object
var array = [];
$.each(obj, function (key, value) {
array.push(key);
if ($.isArray(value)) {
Array.prototype.push.apply(array, value);
}
else {
array.push(value);
}
});
return array;
}
var obj = {"key1" : [1,3,3],"key2" : "val", "key3":23};
var output = flattenObject(obj);
console.log(output);
Fiddle Link -- https://jsfiddle.net/0wu5z79a/1/
小提琴链接——https: //jsfiddle.net/0wu5z79a/1/
EDIT : This solution is valid only for your scenario where you know that the nesting is till one level only else you need to have some recursion for deep inner objects.
编辑:此解决方案仅适用于您知道嵌套直到一层的情况,否则您需要对深层内部对象进行一些递归。
回答by Alex
If you're feeling really lazy then you can make use of the popular NPM library flat.
如果你真的很懒惰,那么你可以使用流行的 NPM 库flat。
Example (from their docs)
示例(来自他们的文档)
var flatten = require('flat')
flatten({
key1: {
keyA: 'valueI'
},
key2: {
keyB: 'valueII'
},
key3: { a: { b: { c: 2 } } }
})
// {
// 'key1.keyA': 'valueI',
// 'key2.keyB': 'valueII',
// 'key3.a.b.c': 2
// }
回答by Module11
This answer is an improvement over @Tofandel 's answer
这个答案是对@Tofandel 答案的改进
The function below will flatten an object to the specified depth. This function uses a loop rather than recursion. You can choose how child property keys are named, the default is 'parent.child'. The result is an array of [key, value]arrays, like Object.entries(). It requires lodash for isPlainObjectand partition(), though you could write your own isPlainObject, partition functions if you wanted to remove the dependency.
下面的函数会将对象展平到指定的深度。此函数使用循环而不是递归。您可以选择子属性键的命名方式,默认为“parent.child”。结果是一个数组[key, value]数组,例如Object.entries(). 它需要 lodash for isPlainObjectand partition(),虽然你可以编写自己的 isPlainObject,如果你想删除依赖项,分区函数。
/**
* Returns an array containing the properties of the given Object in the same format
* as Object.entries(). Goes through child objects to the specified depth,
* flattening the properties and prefixing child keys with a parent key names.
* @param {Object} object to retrieve property values for
* @param {Number} maxDepth the maximum number of times to look at properties of
* properties of the given object.
* Set to 1 to only retrieve the property values of the given object, 2 to get
* properties and sub-properties etc.
* @param {Function} keyPrefixer a function that takes a parent object name, and
* a child object name and returns a string representing the combined name.
* @returns {Array} containing the properties and child properties of the given object.
* Each property is returned as an array [key, value].
* Returns an empty array if object is null, undefined, not-an-object, or empty.
*/
const flattenEntries = (
object,
maxDepth = 2,
keyPrefixer = (parentKey, childKey) => `${parentKey}.${childKey}`) => {
if (!object || !_.isPlainObject(object)) {
return [];
}
// make maxDepth >= 1
maxDepth = Math.max(1, Math.abs(maxDepth));
const entryIsNotAnObject = ([key, val]) => !_.isPlainObject(val);
let [simpleProperties, childObjects] = _.partition(Object.entries(object), entryIsNotAnObject);
let result = simpleProperties;
for (let depth = 1; depth < maxDepth; depth++) {
for (let [childObjectKey, childObject] of childObjects) {
const entries = Object.entries(childObject);
const addParentPrefixToKey = ([key, val]) => [keyPrefixer(childObjectKey, key), val];
const prefixedEntries = entries.map(addParentPrefixToKey);
[simpleProperties, childObjects] = _.partition(prefixedEntries, entryIsNotAnObject);
result = result.concat(simpleProperties);
}
}
return result;
};
const test = {
a: 'one',
b: {
c: 'three',
d: {
e: {
f: ['six', 'six'],
g: 7
}
}
}
};
console.log(flattenEntries(test, 10));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

