将对象映射到ES6中的对象数组

时间:2017-05-17 03:27:24

标签: javascript ecmascript-6

如何在保留键名的同时将对象转换为对象数组?

// 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" ] }
]

4 个答案:

答案 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}))

输出;注意步骤显示为隔行扫描 - 过滤映射结果,重复 - 这意味着每个组合传感器都会为输入数组的每次迭代运行。另请注意,由于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} ]

<强>归因

我对这个问题的启示完全归功于Brian Lonsdorf及其附带的工作:Monoidal Contravariant Functors Are Actually Useful

答案 1 :(得分:4)

.map()返回与原始数组长度相同的数组。像你这样的代码在某些情况下没有返回值的回调将导致元素的值为undefined。解决这个问题的一种方法是首先.filter()输出你不想保留的元素。

无论如何,要获得您想要的密钥名称,您可以使用带有computed property name的对象文字:

{ [key]: obj[key] }

在上下文中:

&#13;
&#13;
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;
&#13;
&#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函数:

&#13;
&#13;
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;
&#13;
&#13;