2016-10-31 112 views
1

我最近愛上了函數式編程,並開始學習ramda.js,但我似乎還沒有進入功能思維。我有2個字符串數組(他們實際上是分割字符串),我想查找第一個字符串中有多少個字符與第二個字符串中的相同位置中的字符相同。 作爲規定,我會做一些沿的線條非常簡單:比較2個數組並找到與Ramda相同的值

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

,但我會做如何使用ramda?

回答

4

「......使用rambda」

這裏的一個方式,你可以做到這一點 - 有數不清的其他方式...

const a = 
    'abcdefg' 

const b = 
    'abcxyzg' 

const countEqualChars = (a, b) => 
    R.sum(R.zipWith(R.equals, a, b)) 

countEqualChars(a,b) 
// 4 

但是...

這基本上是你的函數式編程的錯誤方法。忘記Rambda,直到你對如何以功能方式推理程序有一個很好的理解。如果您不知道Rambda的基本層面如何工作,您將永遠無法體會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 ] ] .concat (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 strats,我們可以從字符串配對每個索引,然後刪除不符合對...

const zip = ([ x, ...xs ], [ y, ...ys ]) => 
 
    x === undefined && y === undefined 
 
    ? [] 
 
    : [ [ x, y ] ] .concat (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 ] ] .concat (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中使用的解決方案相比略有不同。這是因爲編程不是魔術,你會發現很多自己的工具,然後才意識到甚至存在其他工具,或者理解他們做了什麼。

有數百種方法可以解決我剛纔所做的問題,並且在我做出的每一個選擇中都考慮了一些權衡問題。您的整個目標是能夠將您的程序分解爲各個組成部分,並隨時間學習權衡。

比較這一點,試圖理解爲什麼某些函數存在於某個庫中,所以你可以猜測它在哪裏使用它......你將通過這樣做來實現函數式編程,而不是通過複製/粘貼人們的靈巧Rambda -liners。一旦您瞭解了爲什麼equals,zipWithsum存在,您就會知道何時使用它們。

讓我知道如果我能幫助清理別的^ _^

+1

我不能希望一個更完整的一個更好的想法的答案。非常感謝你^^。 –

1

我不能與其他的,出色答卷競爭,但不要忘了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));

+0

'reduce'很好的實際應用 - 我唯一的建議是返回'sum + 1'而不是'sum ++',因爲數字已經是不可變的了。 – naomik

+0

我沒有想到這樣使用它。我一直在使用標準的map/reduce/filter數組方法很長一段時間,但很多時候裏面的函數變得非常大,我不喜歡使用params列表中的索引。雖然好的解決方案 –

相關問題