如何在保留键名的同时将对象转换为对象数组?
// actual
obj = {
key1: null,
key2: "Nelly",
key3: [ "suit", "sweat" ]
}
// expected
arr = [
{ key2: "Nelly" },
{ key3: [ "suit", "sweat" ] }
]
目前我的解决方案是......
var arr = Object.keys(obj).map(key => { if (obj[key]) return { key: obj[key] } });
返回
arr = [
undefined,
{ key: "Nelly" },
{ key: [ "suit", "sweat" ] }
]
答案 0 :(得分:5)
<强>传感器强>
这里有很多答案可以帮助您以实际的方式得出答案 - filter
这个,map
,以及您正在寻找的结果。使用原始for
循环还有其他答案,但这些让你感到难过。
所以你想知道,“是否可以过滤和地图而不必多次迭代数组?”是的,使用传感器
Runnable演示
如果有必要,我可以使用更多代码说明更新此段落。 ES6来找你...
// Trans monoid
const Trans = f => ({
runTrans: f,
concat: ({runTrans: g}) =>
Trans(k => f(g(k)))
})
Trans.empty = () =>
Trans(k => k)
const transduce = (t, m, i) =>
i.reduce(t.runTrans((acc, x) => acc.concat(x)), m.empty())
// complete Array monoid implementation
Array.empty = () => []
// transducers
const mapper = f =>
Trans(k => (acc, x) => k(acc, f(x)))
const filterer = f =>
Trans(k => (acc, x) => f(x) ? k(acc, x) : acc)
const logger = label =>
Trans(k => (acc, x) => (console.log(label, x), k(acc, x)))
// your function, implemented with transducers
const foo = o => {
const t = logger('filtering')
.concat(filterer(k => o[k] !== null))
.concat(logger('mapping'))
.concat(mapper(k => ({ [k]: o[k] })))
.concat(logger('result'))
return transduce(t, Array, Object.keys(o))
}
console.log(foo({a: null, b: 2, c: 3}))
输出;注意步骤显示为隔行扫描 - 过滤,映射,结果,重复 - 这意味着每个组合传感器都会为输入数组的每次迭代运行。另请注意,由于 完成 当然 <强>归因强> 我对这个问题的启示完全归功于Brian Lonsdorf及其附带的工作:Monoidal Contravariant Functors Are Actually Useful a
的值为null
,因此a
没有映射或结果步骤;它直接跳到过滤 b
- 所有这些意味着我们只通过一次
// filtering a
// filtering b
// mapping b
// result { b: 2 }
// filtering c
// mapping c
// result { c: 3 }
// => [ { b: 2 }, { c: 3 } ]
foo
函数有很多console.log
个东西。如果不明显,我们只想删除logger
传感器以供实际实施const foo = o => {
const t = filterer(k => o[k] !== null)
.concat(mapper(k => ({ [k]: o[k] })))
return transduce(t, Array, Object.keys(o))
}
console.log(foo({a: null, b: 2, c: 3}))
// => [ {b: 2}, {c: 3} ]
答案 1 :(得分:4)
.map()
返回与原始数组长度相同的数组。像你这样的代码在某些情况下没有返回值的回调将导致元素的值为undefined
。解决这个问题的一种方法是首先.filter()
输出你不想保留的元素。
无论如何,要获得您想要的密钥名称,您可以使用带有computed property name的对象文字:
{ [key]: obj[key] }
在上下文中:
const obj = {
key1: null,
key2: 'Nelly',
key3: [ 'suit', 'sweat' ]
}
const arr = Object.keys(obj)
.filter(v => obj[v] != null)
.map(key => ({ [key]: obj[key] }))
console.log(arr)
&#13;
答案 2 :(得分:2)
正如@zerkms所说,我不认为使用多个es6函数会改进你的代码。尝试循环!
// actual
let obj = {
key1: null,
key2: "Nelly",
key3: [ "suit", "sweat" ]
};
let arr = [];
let k = Object.keys(obj);
for(let i = 0, len = k.length; i < len; i++) {
let key = k[i];
if (obj[key]) {
arr.push({key: obj[key]});
}
}
答案 3 :(得分:1)
如果使用map
,预期数组的长度将与输入中的键数相同。所以map
在这种情况下是不合适的。我的解决方案是使用如下的reduce函数:
var obj = {
key1: null,
key2: 'Nelly',
key3: [ 'suit', 'sweat' ]
}
var res = Object.keys(obj).reduce(
(acc, curr) => {
// if current key's value is not null
// insert object to the resulting array acc
if (obj[curr]) {
acc.push({[curr] : obj[curr]});
return acc;
}
// if they key value is null, skip it
return acc;
}, [] );
console.log(res);
&#13;