递归"合并"或"延伸"与拉姆达?

时间:2016-07-01 00:49:27

标签: javascript functional-programming ramda.js

我试图使用Lodash's merge找到与Ramda等效的函数,该pull request执行基于关键字的递归对象" merge"或者"延伸"。行为类似于以下内容:

let merged = R.someMethod(
  { name: 'Matt', address: { street: 'Hawthorne', number: 22, suffix: 'Ave' }},
  { address: { street: 'Pine', number: 33 }}
);

console.log(merged);

// => { name: 'Matt', address: { street: 'Pine', number: 33, suffix: 'Ave' }}

我注意到以下rolled back中简要介绍了R.set,但之后不久{{3}}。从那以后,Ramda库是否已捕获此功能?

Ramda中是否提供此功能?

5 个答案:

答案 0 :(得分:6)

可以使用R.mergeWith创建一个相对简单的递归函数。

function deepMerge(a, b) {
  return (R.is(Object, a) && R.is(Object, b)) ? R.mergeWith(deepMerge, a, b) : b;
}

deepMerge({ name: 'Matt', address: { street: 'Hawthorne', number: 22, suffix: 'Ave' }},
          { address: { street: 'Pine', number: 33 }});

//=> {"address": {"number": 33, "street": "Pine", "suffix": "Ave"}, "name": "Matt"}

答案 1 :(得分:5)

Ramda目前不包括这样的功能。

有几次尝试创造一个,但他们似乎建立了这种功能真正需要的概念。

如果您认为值得添加,请随意raise an issue

更新

(两年后。)这最终以几个函数的形式添加:mergeDeepLeftmergeDeepRightmergeDeepWithmergeDeepWithKey

答案 2 :(得分:1)

Ramda现在有几个合并功能:mergeDeepLeftmergeDeepRightmergeDeepWithmergeDeepWithKey

答案 3 :(得分:0)

const { unapply, mergeDeepRight, reduce } = R
const mergeDeepRightAll = unapply(reduce(mergeDeepRight, {}))

console.log(mergeDeepRightAll({a:1, b: {c: 1}},{a:2, d: {f: 2}},{a:3, b: {c:3}}))
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

答案 4 :(得分:0)

从头开始

Ramba库中的新功能意味着您不必自己执行此操作,但是如果维护者从不执行此操作怎么办?当您现在需要某种功能或行为时,您不想被困在等待别人编写代码。

下面,我们实现了自己的递归merge

const isObject = x =>
  Object (x) === x

const merge = (left = {}, right = {}) =>
  Object.entries (right)
    .reduce
      ( (acc, [ k, v ]) =>
          isObject (v) && isObject (left [k])
            ? { ...acc, [k]: merge (left [k], v) }
            : { ...acc, [k]: v }
      , left
      )

我们的合并功能也可以正常工作,并且接受任何两个对象作为输入。

const x =
  { a: 1, b: 1, c: 1 }

const y =
  { b: 2, d: 2 }

console.log (merge (x, y))
// { a: 1, b: 2, c: 1, d: 2 }

如果每个对象都包含一个属性,该属性的值也是一个对象,则merge将再次发生并合并嵌套的对象。

const x =
  { a: { b: { c: 1, d: 1 } } }

const y =
  { a: { b: { c: 2, e: 2 } }, f: 2 }

console.log (merge (x, y))
// { a: { b: { c: 2, d: 1, e: 2 } }, f: 2 }

数组也是人

为了支持merge中的数组,我们引入了一个突变帮助器mut,该助手将[ key, value ]对分配给给定的对象o。数组也被视为对象,因此我们可以使用相同的mut函数来更新数组和对象

请注意,Ramda的合并功能不会尝试合并数组。编写自己的函数的主要优点是,您可以轻松地增强其行为,以满足程序不断发展的要求。

const mut = (o, [ k, v ]) =>
  (o [k] = v, o)

const merge = (left = {}, right = {}) =>
  Object.entries (right)
    .map
      ( ([ k, v ]) =>
          isObject (v) && isObject (left [k])
            ? [ k, merge (left [k], v) ]
            : [ k, v ]
      )
    .reduce (mut, left)

按预期进行浅层合并

const x =
  [ 1, 2, 3, 4, 5 ]

const y =
  [ 0, 0, 0 ]

const z =
  [ , , , , , 6 ]

console.log (merge (x, y))
// [ 0, 0, 0, 4, 5 ]

console.log (merge (y, z))
// [ 0, 0, 0, <2 empty items>, 6 ]

console.log (merge (x, z))
// [ 1, 2, 3, 4, 5, 6 ]

也可以进行深度合并

const x =
  { a: [ { b: 1 }, { c: 1 } ] }

const y =
  { a: [ { d: 2 }, { c: 2 }, { e: 2 } ] }

console.log (merge (x, y))
// { a: [ { b: 1, d: 2 }, { c: 2 }, { e: 2 } ] }

可变合并

也许我们想要一个不限于两个输入的合并功能; mergeAll

const Empty =
  {}

const mergeAll = (first = Empty, ...rest) =>
  first === Empty
    ? first
    : merge (first, mergeAll (...rest))

mergeAll ({ a: 1 }, { b: 2 }, { c: 3 })
// { a: 1, b: 2, c: 3 }

此答案是另一个问题的摘录:How to compare two objects and get key-value pairs of their differences?