首页 > 解决方案 > 在 Ramda 中使用对象创建键值数组

问题描述

我正在使用这样的数据结构

const res = {
                "Id": "7ba",
                "Group": {
                    "Id": "ALL",
                    "Strategy": {
                        "name": "random",
                        "Distribution": {
                            "Origin": 0.5,
                            "V1": 0.4
                        }
                    }
                },
                "Path": {
                    "affiliatePage": {
                        "types": [
                            {
                                "Name": "Origin",
                                "variables": {
                                    "returnUrl": ""
                                }
                            },
                            {
                                "Name": "V1",
                                "variables": {
                                    "returnUrl": "asds"
                                }
                            }
                        ]
                    }
                }
}

但我希望 Path 对象是这样的

Path : [{key :"affiliatePage" , 
           types : [
                            {
                                "Name": "Origin",
                                "variables": {
                                    "returnUrl": ""
                                }
                            },
                            {
                                "Name": "V1",
                                "variables": {
                                    "returnUrl": "asds"
                                }
                            }
                         ]
}]

和分发对象要像

Distribution : [{key : "Origin" , value: 0.5},{key : "V1" , value: 0.4}]

我尝试了以下事情,但没有帮助,不知道我哪里出错了

const mapper = (val) => { key: val , 
                   value:GroupData[val]}
const GroupData = R.path(['Group','Strategy','Distribution'])(res)
const PathParser =  R.ifElse(
    R.isNil(R.prop('Path')),
    R.always(null),
    R.applySpec({
      key: R.keysIn(R.prop('Path'))[0],
      types : R.valuesIn(R.prop('Path'))[0].types
    })
)

const GroupParser =  R.ifElse(
    R.isNil(R.prop('Group')),
    R.always(null),
    R.applySpec({
      Distribution : R.map(mapper, R.keysIn(R.path(['Group', 'Strategy', 'Distribution'])))
    })
)
 const transform = R.applySpec({
  Path: PathParser,
  Group: GroupParser
})
console.log(transform(res))

我收到错误,因为_arity 的第一个参数必须是不大于十的非负整数。 任何建议,将不胜感激。谢谢!

标签: parsingramda.jsreact-gql

解决方案


因为您的转换不相关,所以我能看到的最好的事情是将它们编写为单独的函数,一个可以转换一个Distribution节点,一个可以转换一个Path节点,然后将它们组合成一个函数,或者通过组合基于镜头的函数或使用 Ramda 的evolve.

在这两种情况下,各个函数可能如下所示:

const distFn = pipe (toPairs, map (zipObj (['key', 'value'])))
const pathFn = pipe (toPairs, map (([k, v]) => ({key: k, ...v})))

我敢肯定,如果我们尝试,我们可以让后者毫无意义,但我看不出这样做有什么意义。

基于镜头的解决方案可能如下所示:

const transform = pipe (
  over (lensPath (['Group', 'Strategy', 'Distribution']), distFn),
  over (lensPath (['Path']), pathFn)
) 

const distFn = pipe (toPairs, map (zipObj (['key', 'value'])))
const pathFn = pipe (toPairs, map (([k, v]) => ({key: k, ...v})))

const transform = pipe (
  over (lensPath (['Group', 'Strategy', 'Distribution']), distFn),
  over (lensPath (['Path']), pathFn)
) 

const res = {Id: "7ba", Group: {Id: "ALL", Strategy: {name: "random", Distribution: {Origin: 0.5, V1: 0.4}}}, Path: {affiliatePage: {types: [{Name: "Origin", variables: {returnUrl: ""}}, {Name: "V1", variables: {returnUrl: "asds"}}]}}}

console .log(transform (res))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
<script> const {pipe, toPairs, map, zipObj, over, lensPath} = R          </script>

evolve解决方案可能如下所示:

const transform = evolve ({
  Group: {Strategy: {Distribution: distFn}},
  Path: pathFn
})

const distFn = pipe (toPairs, map (zipObj (['key', 'value'])))
const pathFn = pipe (toPairs, map (([k, v]) => ({key: k, ...v})))

const transform = evolve ({
  Group: {Strategy: {Distribution: distFn}},
  Path: pathFn
})

const res = {Id: "7ba", Group: {Id: "ALL", Strategy: {name: "random", Distribution: {Origin: 0.5, V1: 0.4}}}, Path: {affiliatePage: {types: [{Name: "Origin", variables: {returnUrl: ""}}, {Name: "V1", variables: {returnUrl: "asds"}}]}}}

console .log(transform (res))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>
<script> const {pipe, toPairs, map, zipObj, evolve} = R                  </script>

在任何一种情况下,如果distFn并且pathFn没有在其他地方使用,将它们折叠到 main 函数中并没有什么坏处……除了它可能变得不那么可读并且可能更难以编写测试用例。

两者之间,很难抉择。该lens解决方案使用更常见的函数式编程习惯用法。但是这个evolve更明确一些,并且可能性能稍微好一些(未经测试的猜测。)


推荐阅读