首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用Ramda更新JSON中任何级别的键值?

如何使用Ramda更新JSON中任何级别的键值?
EN

Stack Overflow用户
提问于 2018-08-02 18:33:58
回答 2查看 303关注 0票数 1

有没有一种方法可以找到键的值,它可以出现在任何对象下的任何级别,并使用Ramda更新它?

例如,

JSON-1

代码语言:javascript
复制
{
  "query": {
    "boundary": {
      "type": "polygon",
      "coordinates": "[[-85.33604,35.055749],[-85.33604,35.07499772909699],[-85.279134,35.07499772909699],[-85.279134,35.055749],[-85.33604,35.055749]]"
    }
}

JSON-2

代码语言:javascript
复制
{
  "query": {
    "nearby": {
      "radius": "30mi",
      "coordinates": "[-121.40019800,38.55378300]"
    }
  }
}

在这两个JSON中,我想做一些类似的事情:

query.nearby.coordinates = JSON.parse(query.nearby.coordinates)

query.boundary.coordinates = JSON.parse(query.boundary.coordinates)

只有一种功能。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-08-02 19:21:00

一种方法是遍历对象树,并尝试将找到的任何字符串解析为JSON。

代码语言:javascript
复制
const parseNestedJSON = R.cond([
   [R.is(String), R.tryCatch(JSON.parse, R.nthArg(1))],
   [R.is(Object), obj => R.map(parseNestedJSON, obj)],
   [R.T, R.identity],
])

请注意,这可能会执行一些不需要的转换,例如将{foo: '1'}转换为{foo: 1} (string to number)。

只针对名为coordinates的嵌套键可能更安全

代码语言:javascript
复制
const parseNestedJSON = R.cond([
    [R.has('coordinates'), R.over(R.lensProp('coordinates'), JSON.parse)],
    [R.is(Object), obj => R.map(parseNestedJSON, obj)],
    [R.T, R.identity],
])

编辑:如果coordinates可能不是json,您也可以在这里使用tryCatch

代码语言:javascript
复制
  [R.has('coordinates'), R.over(R.lensProp('coordinates'), R.tryCatch(JSON.parse, R.nthArg(1)))]

用法:

代码语言:javascript
复制
parseNestedJSON({"nearby": {"coordinates": "[-121.40019800,38.55378300]"}})
=> { nearby: { coordinates: [ -121.400198, 38.553783 ] } }
票数 1
EN

Stack Overflow用户

发布于 2018-08-02 21:40:54

另一种选择是定义一个可以负责更新值的镜头。

第一种方法假设可以找到坐标的已知路径的数量是有限的。

代码语言:javascript
复制
// Creates a lens that accepts a list of paths and chooses the first
// matching path that exists in the target object

const somePathLens = paths => toFunctor => target => {
  const path = R.find(
    p => R.pathSatisfies(x => x != null, p, target),
    paths
  )
  return R.map(
    value => R.assocPath(path, value, target),
    toFunctor(R.path(path, target))
  )
}

// R.over can then be used with JSON.parse to parse the first
// matching path that is found.

const parseCoords = R.over(
  somePathLens([
    ['query', 'boundary', 'coordinates'],
    ['query', 'nearby', 'coordinates']
  ]),
  JSON.parse
)

console.log(parseCoords({
  "query": {
    "boundary": {
      "type": "polygon",
      "coordinates": "[[-85.33604,35.055749],[-85.33604,35.07499772909699],[-85.279134,35.07499772909699],[-85.279134,35.055749],[-85.33604,35.055749]]"
    }
  }
}))

console.log(parseCoords({
  "query": {
    "nearby": {
      "radius": "30mi",
      "coordinates": "[-121.40019800,38.55378300]"
    }
  }
}))
代码语言:javascript
复制
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

如果实际路径未知,并且您只需要通过给定的键找到第一个值,则可以使用第二种方法。

代码语言:javascript
复制
// Recursively search for the given key in an object, returning the
// first matching path if found.

const findKeyInPath = (keyToFind, obj) => {
  const findKeyInPath_ = o =>
    R.has(keyToFind, o)
      // if found, return this key as the path
      ? [keyToFind]
      // otherwise find all keys with objects and recursively
      // call this function.
      : R.reduceRight((k, acc) => {
          // find either the subpath of this key, or the subpath
          // found in the remaining keys
          const subPath = R.when(R.isEmpty, _ => acc, findKeyInPath_(o[k]))
          // if the subpath contains a key, prepend it with the
          // current key, otherwise return the empty list
          return R.unless(R.isEmpty, R.prepend(k), subPath)
        }, [], R.filter(k => R.propIs(Object, k, o), R.keys(o)))
  return findKeyInPath_(obj)
}

// Create a lens that recursively searches for the first matching
// key within a target object.

const someKeyLens = key => toFunctor => target => {
  // find the path using our new `findKeyInPath` function
  const path = findKeyInPath(key, target)
  return R.map(
    value => R.assocPath(path, value, target),
    toFunctor(R.path(path, target))
  )
}

const parseCoords = R.over(
  someKeyLens('coordinates'),
  JSON.parse
)

console.log(parseCoords({
  "query": {
    "boundary": {
      "type": "polygon",
      "coordinates": "[[-85.33604,35.055749],[-85.33604,35.07499772909699],[-85.279134,35.07499772909699],[-85.279134,35.055749],[-85.33604,35.055749]]"
    }
  }
}))

console.log(parseCoords({
  "query": {
    "nearby": {
      "radius": "30mi",
      "coordinates": "[-121.40019800,38.55378300]"
    }
  }
}))
代码语言:javascript
复制
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

值得一提的是,只有在保证在目标对象中找到路径的情况下,这些才是有效的镜头,否则行为是未定义的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51651438

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档