使用Ramda或类似工具从非结构化数据阵列创建组

时间:2017-10-19 23:41:35

标签: arrays functional-programming javascript-objects ramda.js

给定一个包含这种形式的对象的数组:

[{data: {set: 'set1', option: 'option1'}},
 {data: {set: 'set1', option: 'option2'}},
 {data: {set: 'set1', option: 'option3'}},
 {data: {set: 'set2', option: 'optionA'}},
 {data: {set: 'set2', option: 'optionB'}}]

如何获得如下所示的数组:

[{set: 'set1', options: ['option1', 'option2', 'option3']},
 {set: 'set2', options: ['optionA', 'optionB']}]

我想使用函数式编程,Ramda或本机JS方法。感谢。

1 个答案:

答案 0 :(得分:3)

我喜欢在几个步骤中考虑这样的问题,这些步骤一直让我朝着我想要的输出方向前进。有时这意味着我会错过一个更优雅的解决方案,但它通常会让我更容易想出一些有效的方法。

所以让我们用Ramda这样看看你的问题。

第1步:删除不必要的数据

您不需要外部data属性。由于您的数据是一个对象列表,并且每个对象都有一个data属性来保存我们想要的数据,因此我们只需在每个对象上调用prop('data')

要在每个上面调用它,我们可以使用map,向我们提供map(prop('data'))

因为这是一种常见的用途,Ramda还提供了一种将mapprop结合起来的功能:pluck('data')。将其应用于您的输入我们得到:

[
  {option: "option1", set: "set1"},
  {option: "option2", set: "set1"},
  {option: "option3", set: "set1"},
  {option: "optionA", set: "set2"}
  {option: "optionB", set: "set2"}
]

这是一个好的开始。现在我们需要考虑将它们组合成类似的组。

第2步:对数据进行分组

我们希望将共享其set属性的所有元素组合在一起。 Ramda提供groupBy,它接受​​一个将项目转换为分组键的函数。我们希望按set属性进行分组,因此我们可以再次使用prop,并针对之前的结果调用groupBy(prop('set'))

这会产生:

{
  set1: [
    {option: "option1", set: "set1"},
    {option: "option2", set: "set1"},
    {option: "option3", set: "set1"},
  ],
  set2: [
    {option: "optionA", set: "set2"}
    {option: "optionB", set: "set2"}
  ]
}

那里有冗余信息。在某个地方,我们需要弄明白这一点。但是当我试图将其他部分拉到一起时,我会保留一点。

第3步:合并选项

我们已经看过pluck。看起来我们可以在set1set2上使用它。好map也适用于对象,所以如果我们只是在最后调用map(pluck('option')),我们就会得到这个:

{
  set1: ["option1", "option2", "option3"], 
  set2: ["optionA", "optionB"]
}
哦,看,那也摆脱了冗余。这看起来非常接近所需的输出。

第4步:重建对象

但是现在我没有看到内置的Ramda功能会让我一路走来。我可以写一个自定义的。或者我可以通过两个步骤来转换它。知道我想使用Ramda的zipObj函数,我可以先通过toPairs将上面的内容转换为数组,生成:

[
  ["set1", ["option1", "option2", "option3"]], 
  ["set2", ["optionA", "optionB"]]
]

然后我可以使用我希望每个属性拥有的键在结果上映射zipObj。这意味着我可以致电map(zipObj(['set', 'options']))以获得最终的预期结果:

[
  {
    set: "set1",
    options: ["option1", "option2", "option3"]
  },
  {
    set: "set2",
    options: ["optionA", "optionB"]
  }
]

第5步:全部放在一起

好的,现在我们必须把它们放在一起。 Ramda有pipecompose。我通常只在适合一行时选择compose。因此,将这些与pipe合并,我们可以写下:

const transform = pipe(
  pluck('data'),
  groupBy(prop('set')),
  map(pluck('option')),
  toPairs,
  map(zipObj(['set', 'options']))
)

然后将其称为

transform(myObj)

您可以在 Ramda REPL 上查看此操作。在那里你可以注释掉pipe里面的后面的行,看看早先的行。

我在那里构建了代码,一次向管道添加一行,直到我转换了数据。我认为这是一种很好的工作方式。