用Ramda比较两个数组并找到相等的值
Comparing 2 arrays and finding equal values with Ramda
我最近爱上了函数式编程,并开始学习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 ]
结合这些zip
和filter
策略,我们可以从字符串中配对每个索引,然后删除不匹配的对…
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一行程序,您将擅长函数式编程。一旦你理解了为什么 equals
、zipWith
和sum
存在,你就知道什么时候使用它们了。
我无法与另一个竞争,优秀的答案,但不要忘记array
原型有许多有用的方法,如filter
或reduce
!
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]
- 如何使用 node.js 比较两个 json 数组
- 用每小时的差值填充数组/列表-从下拉列表中给定两个时间值
- 访问$.ajax()函数中的两个不同数组
- 正在更新mongod中两个对象内部的数组
- 如何使用javascript合并两个对象数组
- 比较包含多个值对的两个JavaScript数组
- jQuery对象从html表中查询为两个一维数组,用于Chartist图表
- 检查来自不同数组的两个元素的一个属性是否相等
- 如何在javascript中合并两个对象数组
- 如何获取数组第一个元素的范围
- 捕获一组两个特殊字符之间的所有内容,但允许角色在正文中出现一次
- 使用具有不同属性数的两个或多个着色器时发生冲突
- JSON数组-多个有效答案的可能性
- 编写一个函数,将数组(第一个参数)拆分为大小(第二个参数)的长度组,并将它们作为多维数组返回
- 如何添加值到javascript数组两次或更多
- 使用.shift()更新数组'5个元素
- JavaScript 过滤器数组多个条件
- 如果数组第一个元素中的字符串包含数组第二个元素中字符串的所有字母,则返回true
- Javascript序列化数组多个表单问题
- 编写一个函数,将数组(第一个参数)拆分为大小相同的组(第二个参数),并将其作为多维数组返回