【发布时间】:2016-07-08 01:28:47
【问题描述】:
更新:我以错误的方式描述了问题,并完全重写了描述,以及有效但丑陋和有限的代码。
假设有一个对象
const input = {
a: 1,
b: '2',
c: {
d: true,
e: '4'
},
f: [{
g: 5,
h: {
i: '6'
}
}, {
g: 7,
h: {
i: '8'
}
}]
}
我正在寻找的是所有可能的嵌套数组排列的集合,对象的键被展平并用“.”连接,例如
[{
a: 1,
b: '2',
'c.d': true,
'c.e': '4',
'f.g': 5,
'f.h.i': '6'
}, {
a: 1,
b: '2',
'c.d': true,
'c.e': '4',
'f.g': 7,
'f.h.i': '8'
}]
请注意,没有任何键具有非原始值,例如,'f.h' 会指向一个对象。
所以,我首先要做的是收集所有键,并人为地将# 符号添加到指向数组项的每个键,所以# 的意思是“该数组中的每个索引”:
function columns(data, prefix = '') {
if (_.isArray(data)) {
return columns(_.first(data), `${prefix}.#`);
} else if (_.isObject(data)) {
return _.filter(_.flatMap(_.keys(data), key => {
return _.concat(
!_.isObject(_.result(data, key)) ? `${prefix}.${key}` : null,
columns(data[key], `${prefix}.${key}`)
);
}));
} else {
return null;
}
}
console.log(columns(input)); // -> [".a", ".b", ".c.d", ".c.e", ".f.#.g", ".f.#.h.i"]
现在,我使用 lodash。前导“。” in keys 对 lodash 来说不是问题,所以我就让它保持原样。使用 lodash,我将对象压缩成一个带有奇怪键的单级对象:
function flattenKeys(original, keys) {
return _.mapValues(_.groupBy(_.map(keys, key => ({
key,
value: _.result(original, key)
})), 'key'), e => _.result(e, '0.value'));
}
console.log(flattenKeys(input, columns(input))) // -> {".a":1,".b":"2",".c.d":true,".c.e":"4"}
现在我(以一种非常错误的方式)运行原始对象的每个类似数组的属性并生成一个对象数组,将.f.#.h.i 之类的键设置为第一个元素的.f.0.h.i 值等:
function unfold(original, keys, iterables) {
if (!_.isArray(iterables)) {
return unfold(original, keys, _.uniq(_.map(_.filter(keys, key => /#/i.test(key)), key => _.replace(key, /\.\#.*/, ''))));
} else if (_.isEmpty(iterables)) {
return [];
} else {
const first = _.first(iterables);
const rest = _.tail(iterables);
const values = _.result(original, first);
const flatKeys = _.mapKeys(_.filter(keys, key => _.includes(key, first)));
const updated = _.map(values, (v, i) => ({
...flattenKeys(original, keys),
..._.mapValues(flatKeys, k => _.result(original, _.replace(k, /\#/, i)))
}));
return _.concat(updated, unfold(original, keys, rest));
}
}
console.log(unfold(input, columns(input))) // -> [{".a":1,".b":"2",".c.d":true,".c.e":"4",".f.#.g":5,".f.#.h.i":"6"},{".a":1,".b":"2",".c.d":true,".c.e":"4",".f.#.g":7,".f.#.h.i":"8"}]
所以最后,我只需要清理密钥,事实上,在我的情况下,这不是必需的。
问题是,除了代码的丑陋之外,我怎样才能使它与原始对象中可能的多个类似数组的属性一起工作?
现在,我明白了,这个问题更适合 CodeReview StackExchange,所以如果有人把它转移到那里,我可以接受。
【问题讨论】:
-
是只有两层还是任意多?
-
这些数组中是否总是只有一个元素?如果不是,那意味着什么?如果是的话,你为什么首先使用这些数组?
-
刚刚发现一个数组可能包含多个元素,但永远不会为空。我有工作代码,但是伙计,这有多讨厌。不过,我会分享它。
-
更新后的示例与之前的示例完全不同,现在每个对象都包含所有扁平键。而且完全不清楚您是如何得出
'f.g': 7和'f.h.i': '8'的值的。请修复示例;最好包括多个。 -
当然,已更新。我差一点就删除这个问题了????但是为了历史而持有它,并且相信有人可能会在完全相同的设置下遇到相同的组合问题。
标签: javascript arrays recursion combinatorics