admin管理员组

文章数量:1332708

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. 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. 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?

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. 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. 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?

Share Improve this question asked Oct 31, 2016 at 15:59 N. SilvestrinN. Silvestrin 211 silver badge5 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 7

"... using 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. You'll never be able to appreciate Rambda's convenience if you don't know how things are working at a fundamental level.

Start by learning about recursion as an alternative to for/while loops. 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 parison, 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

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...

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. 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 bee 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. Once you understand why equals, zipWith, and sum exist, you'll know when to use them.

I can't pete with the other, excellent answer, but don't forget the array prototype has many useful methods such as filter or 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));

Might want to take a look at intersection if you're just looking to see what elements the two arrays have in mon.

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

本文标签: javascriptComparing 2 arrays and finding equal values with RamdaStack Overflow