用Ramda比较两个数组并找到相等的值

Comparing 2 arrays and finding equal values with Ramda

本文关键字:数组 两个 比较 Ramda      更新时间:2023-09-26

我最近爱上了函数式编程,并开始学习ramda.js,但我似乎还不能进入函数式思维模式。我有两个字符串数组(它们实际上是分裂的字符串),我想找出第一个字符串中有多少字符等于第二个字符串中相同位置的字符。我必须做一些非常简单的事情,比如:

let counter = 0
for(let i = 0; i < array.length; i++){
  if(firstArray[i] === secondArray[i]) counter++
}

但是我怎么用ramda呢?

"……使用rambda "

这里有一种方法可以做到这一点-还有无数其他方法…

const countEqualChars = (a, b) =>
  R.sum(R.zipWith(R.equals, a, b))
countEqualChars(
  [ 'a', 'b', 'c', 'd', 'e', 'f', 'g' ],
  [ 'a', 'b', 'c', 'x', 'y', 'z', 'g' ]
)
// 4
countEqualChars('abcdefg', 'abcxyzg')
// 4

但是…

这基本上是你处理函数式编程的错误方式。忘记ramda吧,直到你对如何用函数式的方式推理程序有了很好的理解。如果你不知道事物在基本层面上是如何工作的,你将永远无法欣赏Rambda的便利性。

首先学习递归作为for/while循环的替代方案。循环没有错,但递归有时会让你用更好的方式表达…

const a =
  'abcdefg'
const b =
  'abcxyzg'
const countEqualChars = ([ x, ...xs ], [ y, ...ys ]) =>
{ if (x === undefined || y === undefined)
    return 0
  else if (x === y)
    return 1 + countEqualChars (xs, ys)
  else
    return countEqualChars (xs, ys)
}
console.log (countEqualChars (a, b))
// 4

现在我们看到这个函数做了很多事情。我们一次检查一个元素,做一些比较,和一些计数。也许我们可以把它分解成一些单独的任务这样我们的函数就更容易维护了。让我们从一个函数开始,它允许我们将两个数组的相等下标配对…

const zip = ([ x, ...xs ], [ y, ...ys ]) =>
  x === undefined && y === undefined
    ? []
    : [ [ x, y ], ...zip (xs, ys) ]
console.log (zip ([ 1, 2, 3 ], [ 'a', 'b', 'c' ]))
// [ [ 1, 'a' ]
// , [ 2, 'b' ]
// , [ 3, 'c' ]
// ]

接下来,我们可以使用内置的filter函数创建一个只包含我们想要的元素的新数组

const xs =
  [ 1, 1, 2, 2, 3, 3, 4, 4 ]
const justThrees =
  xs.filter (x => x === 3)
console.log (justThrees)
// [ 3, 3 ]

结合这些zipfilter策略,我们可以从字符串中配对每个索引,然后删除不匹配的对…

const zip = ([ x, ...xs ], [ y, ...ys ]) =>
  x === undefined && y === undefined
    ? []
    : [ [ x, y ], ...zip (xs, ys) ]
const eq = (x, y) =>
  x === y
const apply = f => xs =>
  f (...xs)
const a =
  'abcdefg'
const b =
  'abcxyzgh'
const matches =
  zip (a, b) .filter (apply (eq))
console.log (matches)
// [ [ 'a', 'a' ]
// , [ 'b', 'b' ]
// , [ 'c', 'c' ]
// , [ 'g', 'g' ]
// ]

现在剩下的就是计算匹配对了。我们将把整个东西也变成一个函数,以便您可以在需要时重用它

const zip = ([ x, ...xs ], [ y, ...ys ]) =>
  x === undefined && y === undefined
    ? []
    : [ [ x, y ], ...zip (xs, ys) ]
const eq = (x, y) =>
  x === y
const apply = f => xs =>
  f (...xs)
const countEqualChars = (a, b) =>
  zip (a, b)
    .filter (apply (eq))
    .length
console.log (countEqualChars ('abcdefg', 'abcxyzgh'))
// 4

你会发现我们手工推导的解与我们用的解有些许的不同。这是因为编程不是魔法,在你意识到其他工具的存在或理解它们的作用之前,你会发明很多自己的工具。

有上百种方法可以解决我刚刚做的问题,我做的每一个选择都需要权衡。您的全部目标是能够将您的程序分解为其组成部分,并随着时间的推移了解权衡。

与试图理解为什么某个函数存在于某个库中只是为了猜测在哪里使用它相比…通过这样做,而不是复制/粘贴人们聪明的Rambda一行程序,您将擅长函数式编程。一旦你理解了为什么 equalszipWithsum存在,你就知道什么时候使用它们了。

我无法与另一个竞争,优秀的答案,但不要忘记array原型有许多有用的方法,如filterreduce !

var countMatches = (a, b) => a.reduce((sum, c, i) => 
  b[i] === c 
    ? ++sum 
    : sum
, 0);
var set1 = "1234678".split("");
var set2 = "1234568".split("");
console.log(countMatches(set1, set2));

如果你只是想看看这两个数组有什么共同的元素,你可能想看看交集。

R.intersection([1,2,3,4], [7,6,5,4,3]); //=> [4, 3]