2014-01-06 234 views
5

我對Scala和整個函數式編程風格都很陌生。我需要做的是通過比較兩個字的每個字母來計算兩個字符串之間的相似度。該功能將與相同長度的單詞一起使用。在Scala中避免循環

例如,「網絡」和「鍛鍊」將有1「豪斯醫生」和「鼠標」的相似性將有4

這裏的相似性是我會怎麼做它在一個很老土C#的方式:

int calculateCharSimilarity(string first, string second) 
{ 
    int similarity = 0; 
    for(int i = 0; i < first.lenght() && i < first.lenght(); i++) 
    { 
    if(first.charAt(i) == second.charAt(i)) 
     similarity++; 
    } 
    return similarity; 
} 

我在斯卡拉這樣做多遠才能寫出一個尾遞歸函數,以避免循環:

@tailrec 
private def calculateCharSimilarity(first: Seq[Char], second: Seq[Char], similarity: Int = 0): Int = { 
    if(first != Nil && second != Nil) 
    calculateCharSimilarity(first.tail, second.tail, if(first.head == second.head) similarity + 1 else similarity) 
    else 
    similarity 
} 

但我不敢肯定,如果這是最好的做法斯卡拉。例如,是否有任何方法可以使Collection Combinators(zip,filter)更優雅?

回答

10
def charSimilarity(first: String, second: String) = 
    (first.view zip second).count{case (a, b) => a == b} 

charSimilarity("network", "workout") 
// Int = 1 

charSimilarity("House", "Mouse") 
// Int = 4 

您可以在這裏刪除方法view。在這種情況下,您將創建大小爲min(first.size, second.size)的元組(Char, Char)的新集合。對於小字符串(單個單詞),您將不會遇到任何性能問題。

備選實現:

(first, second).zipped.count{case (a, b) => a == b} 
+0

爲了完整性和將來的參考,在C#中相同的方法的主體可以是'返回first.Zip(第二,Tuple.Create).Count之間的(T => t.Item1 == t.Item2);',非常相似。 :) –

+3

@PatrykĆwiek:我猜'first.Zip(second,(a,b)=> a == b).Count(t => t)'更好(沒有不必要的'Tuple'創作,我只是不喜歡'ItemN'和'_N'方法)。 – senia

+0

真的很好,趕上!不幸的是,C#缺乏語法糖,並支持類似於Scala和F#的元組,我只是想盡可能接近您的解決方案。 –