Javascript:展平对象内的任何数组值(嵌套)
Javascript: Flatten any array values within object (nested)
我想展平对象中的 any 数组值,例如就像下面的 sample
。该解决方案不应仅适用于 ecommerce
,而应适用于任何可能作为数组类型存在于对象中的字面意思。示例:
var sample = {
price: "999",
description: "...",
ecommerce: {
products: [
{
brand: "apple",
category: "phone"
},
{
brand: "google",
category: "services"
}
]
}
};
我希望输出为:
{
price: "999",
description: "..."
ecommerce: {
products_1: {
brand: "apple",
category: "phone"
},
products_2: {
brand: "google",
category: "services"
}
}
}
在 JavaScript (ES6/7) 中最有效的方法是什么?
提前致谢!
由于评论和一些缺点而更新!!!如果那些在最初提出问题时如此快速地点击减号的人能够撤销它,那就太好了!
我已经试过了,这是完全错误的,我也确信有更好的功能方法来做到这一点:
function flattenArray(array) {
var obj = array.reduce((acc, cur, i) => {
acc[i] = cur;
return acc;
}, {});
return obj;
}
function cleanObject(object) {
for (let key in object) {
let testObject = object[key];
if (Array.isArray(testObject)) {
testObject = flattenArray(testObject)
} else if (typeof(testObject) === 'object') {
testObject = cleanObject(testObject);
}
return testObject;
}
return object;
}
var clean = cleanObject(sample);
更新 2: 鉴于这两种解决方案都如此专注于 ecommerce
如果下一个对象是:
,解决方案将如何工作
var sample = {
price: "999",
description: "...",
differentArray: [
{
brand: "apple",
category: "phone"
},
{
brand: "google",
category: "services"
}
]
};
请注意,这不仅是不同的 key
,而且嵌套级别也不同。
我会做什么:
const sample = {
price: "999",
description: "...",
ecommerce: {
products: [
{
brand: "apple",
category: "phone"
},
{
brand: "google",
category: "services"
}
]
}
}
sample.ecommerce.products.forEach((p, i) => {
sample.ecommerce['products_' + i] = p
})
delete sample.ecommerce.products
console.log(sample)
只需 reduce ecommerce
数组并根据需要销毁每个元素。
const sample = {
price: "999",
description: "...",
ecommerce: {
products: [
{
brand: "apple",
category: "phone"
},
{
brand: "google",
category: "services"
}
]
}
}
const flattenArray = (arr, key) =>
arr.reduce((prev, curr, index) => {
return {
...prev,
[`${key}_${index + 1}`]: curr,
}
}, {})
const result = {
...sample,
ecommerce: flattenArray(sample.ecommerce.products, 'products'),
}
console.log(result)
递归应用的基于 Array#reduce
的方法可以完成这种键值袋的工作,...第一个通用解决方案可能看起来像这样...
function recursivelyMapArrayItemsToGenericKeys(collector, key) {
var
source = collector.source,
target = collector.target,
type = source[key];
if (Array.isArray(type)) {
type.forEach(function (item, idx) {
var
keyList = Object.keys(item || ''),
genericKey = [key, idx].join('_');
if (keyList.length >= 1) {
target[genericKey] = keyList.reduce(recursivelyMapArrayItemsToGenericKeys, {
source: item,
target: {}
}).target;
} else {
target[genericKey] = item;
}
});
} else if (typeof type !== 'string') {
var keyList = Object.keys(type || '');
if (keyList.length >= 1) {
target[key] = keyList.reduce(recursivelyMapArrayItemsToGenericKeys, {
source: type,
target: {}
}).target;
} else {
target[key] = type;
}
} else {
target[key] = type;
}
return collector;
}
var sample = {
price: "999",
description: "...",
ecommerce: {
products: [{
brand: "apple",
category: "phone"
}, {
brand: "google",
category: "services"
}, {
foo: [{
brand: "bar",
category: "biz"
}, {
brand: "baz",
category: "biz"
}]
}]
}
};
var result = Object.keys(sample).reduce(recursivelyMapArrayItemsToGenericKeys, {
source: sample,
target: {}
}).target;
console.log('sample : ', sample);
console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }
...在下一个代码清理步骤中,可能会摆脱重复的逻辑,从而以两个函数和一个 alternating/reciprocal 递归结束...
function recursivelyAssignItemsFromTypeByKeys(target, type, keyList, key) {
if (keyList.length >= 1) {
target[key] = keyList.reduce(recursivelyMapArrayItemsToGenericKeys, {
source: type,
target: {}
}).target;
} else {
target[key] = type;
}
}
function recursivelyMapArrayItemsToGenericKeys(collector, key) {
var
source = collector.source,
target = collector.target,
type = source[key];
if (Array.isArray(type)) {
type.forEach(function (item, idx) {
var
keyList = Object.keys(item || ''),
genericKey = [key, idx].join('_');
recursivelyAssignItemsFromTypeByKeys(target, item, keyList, genericKey);
});
} else if (typeof type !== 'string') {
var keyList = Object.keys(type || '');
recursivelyAssignItemsFromTypeByKeys(target, type, keyList, key);
} else {
target[key] = type;
}
return collector;
}
var sample = {
price: "999",
description: "...",
ecommerce: {
products: [{
brand: "apple",
category: "phone"
}, {
brand: "google",
category: "services"
}, {
foo: [{
brand: "bar",
category: "biz"
}, {
brand: "baz",
category: "biz"
}]
}]
}
};
var result = Object.keys(sample).reduce(recursivelyMapArrayItemsToGenericKeys, {
source: sample,
target: {}
}).target;
console.log('sample : ', sample);
console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }
我想展平对象中的 any 数组值,例如就像下面的 sample
。该解决方案不应仅适用于 ecommerce
,而应适用于任何可能作为数组类型存在于对象中的字面意思。示例:
var sample = {
price: "999",
description: "...",
ecommerce: {
products: [
{
brand: "apple",
category: "phone"
},
{
brand: "google",
category: "services"
}
]
}
};
我希望输出为:
{
price: "999",
description: "..."
ecommerce: {
products_1: {
brand: "apple",
category: "phone"
},
products_2: {
brand: "google",
category: "services"
}
}
}
在 JavaScript (ES6/7) 中最有效的方法是什么?
提前致谢!
由于评论和一些缺点而更新!!!如果那些在最初提出问题时如此快速地点击减号的人能够撤销它,那就太好了!
我已经试过了,这是完全错误的,我也确信有更好的功能方法来做到这一点:
function flattenArray(array) {
var obj = array.reduce((acc, cur, i) => {
acc[i] = cur;
return acc;
}, {});
return obj;
}
function cleanObject(object) {
for (let key in object) {
let testObject = object[key];
if (Array.isArray(testObject)) {
testObject = flattenArray(testObject)
} else if (typeof(testObject) === 'object') {
testObject = cleanObject(testObject);
}
return testObject;
}
return object;
}
var clean = cleanObject(sample);
更新 2: 鉴于这两种解决方案都如此专注于 ecommerce
如果下一个对象是:
var sample = {
price: "999",
description: "...",
differentArray: [
{
brand: "apple",
category: "phone"
},
{
brand: "google",
category: "services"
}
]
};
请注意,这不仅是不同的 key
,而且嵌套级别也不同。
我会做什么:
const sample = {
price: "999",
description: "...",
ecommerce: {
products: [
{
brand: "apple",
category: "phone"
},
{
brand: "google",
category: "services"
}
]
}
}
sample.ecommerce.products.forEach((p, i) => {
sample.ecommerce['products_' + i] = p
})
delete sample.ecommerce.products
console.log(sample)
只需 reduce ecommerce
数组并根据需要销毁每个元素。
const sample = {
price: "999",
description: "...",
ecommerce: {
products: [
{
brand: "apple",
category: "phone"
},
{
brand: "google",
category: "services"
}
]
}
}
const flattenArray = (arr, key) =>
arr.reduce((prev, curr, index) => {
return {
...prev,
[`${key}_${index + 1}`]: curr,
}
}, {})
const result = {
...sample,
ecommerce: flattenArray(sample.ecommerce.products, 'products'),
}
console.log(result)
递归应用的基于 Array#reduce
的方法可以完成这种键值袋的工作,...第一个通用解决方案可能看起来像这样...
function recursivelyMapArrayItemsToGenericKeys(collector, key) {
var
source = collector.source,
target = collector.target,
type = source[key];
if (Array.isArray(type)) {
type.forEach(function (item, idx) {
var
keyList = Object.keys(item || ''),
genericKey = [key, idx].join('_');
if (keyList.length >= 1) {
target[genericKey] = keyList.reduce(recursivelyMapArrayItemsToGenericKeys, {
source: item,
target: {}
}).target;
} else {
target[genericKey] = item;
}
});
} else if (typeof type !== 'string') {
var keyList = Object.keys(type || '');
if (keyList.length >= 1) {
target[key] = keyList.reduce(recursivelyMapArrayItemsToGenericKeys, {
source: type,
target: {}
}).target;
} else {
target[key] = type;
}
} else {
target[key] = type;
}
return collector;
}
var sample = {
price: "999",
description: "...",
ecommerce: {
products: [{
brand: "apple",
category: "phone"
}, {
brand: "google",
category: "services"
}, {
foo: [{
brand: "bar",
category: "biz"
}, {
brand: "baz",
category: "biz"
}]
}]
}
};
var result = Object.keys(sample).reduce(recursivelyMapArrayItemsToGenericKeys, {
source: sample,
target: {}
}).target;
console.log('sample : ', sample);
console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }
...在下一个代码清理步骤中,可能会摆脱重复的逻辑,从而以两个函数和一个 alternating/reciprocal 递归结束...
function recursivelyAssignItemsFromTypeByKeys(target, type, keyList, key) {
if (keyList.length >= 1) {
target[key] = keyList.reduce(recursivelyMapArrayItemsToGenericKeys, {
source: type,
target: {}
}).target;
} else {
target[key] = type;
}
}
function recursivelyMapArrayItemsToGenericKeys(collector, key) {
var
source = collector.source,
target = collector.target,
type = source[key];
if (Array.isArray(type)) {
type.forEach(function (item, idx) {
var
keyList = Object.keys(item || ''),
genericKey = [key, idx].join('_');
recursivelyAssignItemsFromTypeByKeys(target, item, keyList, genericKey);
});
} else if (typeof type !== 'string') {
var keyList = Object.keys(type || '');
recursivelyAssignItemsFromTypeByKeys(target, type, keyList, key);
} else {
target[key] = type;
}
return collector;
}
var sample = {
price: "999",
description: "...",
ecommerce: {
products: [{
brand: "apple",
category: "phone"
}, {
brand: "google",
category: "services"
}, {
foo: [{
brand: "bar",
category: "biz"
}, {
brand: "baz",
category: "biz"
}]
}]
}
};
var result = Object.keys(sample).reduce(recursivelyMapArrayItemsToGenericKeys, {
source: sample,
target: {}
}).target;
console.log('sample : ', sample);
console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }