简体   繁体   English

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

[英]Comparing 2 arrays and finding equal values with Ramda

I recently fell in love with functional programming, and started learning ramda.js, but i can't seem to get into the functional mindset just yet. 我最近爱上了函数编程,并开始学习ramda.js,但是我似乎还无法进入函数思维方式。 I have 2 arrays of strings(they are actually splitted strings) and i want to find how many characters in the first string are equal to the ones in the same position in the second string. 我有2个字符串数组(它们实际上是分割后的字符串),我想找出第一个字符串中的多少个字符等于第二个字符串中相同位置的那些字符。 Imperatively i would do something really simple along the lines of: 迫切需要按照以下方式做一些非常简单的事情:

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

but how would i do it using ramda? 但是我怎么用ramda呢?

"... using rambda" “ ...使用rambda”

Here's one way you can do it – there are countless other ways ... 这是您可以做到的一种方法-还有无数其他方法...

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

But ... 但是...

That's basically the wrong way for you to approach functional programming. 这基本上是您进行函数式编程的错误方法。 Forget Rambda until you have a good sense for how to reason about programs in a functional way. 忘记Rambda,直到您对如何以功能性方式推理程序有了很好的认识。 You'll never be able to appreciate Rambda's convenience if you don't know how things are working at a fundamental level. 如果您不知道事情在根本上是如何工作的,您将永远无法欣赏Rambda的便利。

Start by learning about recursion as an alternative to for/while loops. 从了解递归作为for/while循环的替代方法开始。 There's nothing wrong with loops, but recursion will allow you to express things in a nicer way sometimes ... 循环没有什么问题,但是递归有时会允许您以更好的方式表达事物……

 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 

Now we see that this function is doing quite a bit. 现在,我们看到此功能做了很多工作。 We're inspecting arrays one element at a time, doing some comparison, and some counting. 我们一次检查一个元素的数组,进行比较和计数。 Maybe we could break that up into some separate tasks so that our function is a little more maintainable over time. 也许我们可以将其分解为一些单独的任务,以使我们的功能随着时间的推移更加可维护。 Let's start with a function that allows us to pair up equal indices of two arrays ... 让我们从一个允许我们配对两个数组的相等索引的函数开始...

 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' ] // ] 

Next, we can use the built-in filter function to make a new array containing only the things we want 接下来,我们可以使用内置的filter函数创建一个仅包含我们想要的东西的新数组

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

Combining those zip and filter strats, we can pair up each index from the strings, then remove the pairs that don't match... 结合这些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' ] // ] 

Now all that's left is counting up the matching pairs. 现在剩下的就是计算匹配对。 We'll make the whole thing into a function too so that you can re-use it as needed 我们也将整个事情变成一个函数,以便您可以根据需要重新使用它

 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 

most importantly ... 最重要的是 ...

You'll see that the solution we derived by hand is slightly different than the one that we used with Rambda. 您会看到,我们手工得出的解决方案与Rambda所使用的解决方案略有不同 That's because programming isn't magic and you'll be inventing a lot of your own tools before you realize what other tools even exist or understand what they do. 那是因为编程并不是魔术,在意识到其他工具甚至不知道它们在做什么之前,您将发明许多自己的工具。

There's hundreds of way to solve the problem I just did, and there's trade-offs I considered with every choice I made. 有数百种方法可以解决我刚刚遇到的问题,并且我在做出的每个选择中都需要权衡取舍。 Your whole goal is to become able to break your program down into its constituent parts and learn the trade-offs over time. 您的总体目标是能够将您的程序分解为各个组成部分,并随着时间的流逝而学习取舍。

Compare that to trying to understand why some function exists in some library just so you can guess where to use it... You'll get good at functional programming by doing it, not by copy/pasting people's clever Rambda one-liners. 将其与试图理解为什么某个函数存在于某个库中只是为了让您可以猜测要在哪里使用它进行比较……通过这样做,您将擅长进行函数式编程,而无需复制/粘贴人们聪明的Rambda单行代码。 Once you understand why equals , zipWith , and sum exist, you'll know when to use them. 一旦了解了为什么 equalszipWithsum存在,就知道何时使用它们。

I can't compete with the other, excellent answer, but don't forget the array prototype has many useful methods such as filter or reduce ! 我无法与其他出色的答案竞争,但不要忘记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]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM