Functional programming 如何从功能上解决赎金券问题
编写一个函数,给出一个字母列表和一个单词,如果可以使用列表中的字母拼写单词,则返回true;如果不能,则返回false。例如,一个列表Functional programming 如何从功能上解决赎金券问题,functional-programming,f#,Functional Programming,F#,编写一个函数,给出一个字母列表和一个单词,如果可以使用列表中的字母拼写单词,则返回true;如果不能,则返回false。例如,一个列表 ['a';'b';'d';'e';'a'] 这个词呢 bed 函数应该返回true。 如果单词是bbed,它也应该返回false,因为列表中只有一个b 通过在for循环中改变字典的状态,这是很容易做到的,但是如何在没有变化的情况下以更具功能性的方式做到这一点呢 这是我做的命令式版本: open System.Collections.Generic let
['a';'b';'d';'e';'a']
这个词呢
bed
函数应该返回true。
如果单词是bbed
,它也应该返回false,因为列表中只有一个b
通过在for循环中改变字典的状态,这是很容易做到的,但是如何在没有变化的情况下以更具功能性的方式做到这一点呢
这是我做的命令式版本:
open System.Collections.Generic
let letters = new Dictionary<char,int>()
[ ('a', 2); ('b', 1); ('c', 1); ('e', 1) ] |> Seq.iter letters.Add
let can_spell (word : string) =
let mutable result = true
for x in word do
if letters.ContainsKey x && letters.[x] > 0 then
let old = letters.[x]
letters.[x] <- old - 1
else
result <- false
done
result
open System.Collections.Generic
let letters=新字典()
[('a',2);('b',1);('c',1);('e',1)]|>以下字母。添加
让我们拼写(单词:string)=
让可变结果=真
对于worddo中的x
如果letters.ContainsKey x&&letters.[x]>0,则
让旧=字母[x]
字母。[x]我想这样做:
let can_spell2 letters word =
let uniqueLettersCount = //group unique letters from words and count them
word |> Seq.groupBy id
|> Seq.map (fun (l,s) -> l,Seq.length s)
uniqueLettersCount //keep taking the sequence until you don't find a key or the key count is below the unique letter number
|> Seq.takeWhile (fun (c,n) ->
match Map.tryFind c letters with
| Some n' -> if n' >= n then true else false
| None -> false)
|> fun s -> if Seq.length s = Seq.length uniqueLettersCount then true else false //if takeWhile didn't stop, the word is allowed
编辑:
用法示例:
let letters = ['a',2;'b',1;'c',1;'e',1] |> Map.ofList
can_spell2 letters "aab" //true
can_spell2 letters "aaba" //false
can_spell2 letters "bf" //false
can_spell2 letters "ecaba" //true
您可以使用两个词典按单词的字母和现有字母跟踪计数,然后检查字母计数是否大于单词的字母计数:
let contains (word:string)(letters:IDictionary<char,int>) =
let w = word
|>Seq.countBy id
|>dict
w.Keys
|>Seq.map(fun k-> letters.ContainsKey k && letters.[k] >= w.[k])
|>Seq.reduce(&&)
这很容易。不是使用可变变量,而是在每次需要重新分配时调用函数。如果您不知道预先调用函数的次数,可以求助于递归。
let letters =
[ ('a', 2); ('b', 1); ('c', 1); ('e', 1); ('d', 1)]
|> dict
contains "bed" letters // True