【问题标题】:Create groups from an unstructured data array using Ramda or similar使用 Ramda 或类似工具从非结构化数据数组创建组
【发布时间】:2018-04-01 02:40:07
【问题描述】:

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

[{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 方法。谢谢。

【问题讨论】:

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


    【解决方案1】:

    我喜欢通过几个步骤来思考这样的问题,这些步骤不断推动我朝着我想要的输出方向前进。有时这意味着我错过了一个更优雅的解决方案,但它通常更容易想出一些可行的方法。

    那么让我们用 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 中后面的行,看看前面的行做了什么。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多