3

このF#コードを記述して、リスト内の単語の頻度をカウントし、タプルをC#に返します。コードをより効率的または短くするにはどうすればよいですか?

let rec internal countword2 (tail : string list) wrd ((last : string list), count) =
match tail with
| [] -> last, wrd, count
| h::t -> countword2 t wrd (if h = wrd then last, count+1 else last @ [h], count)

let internal countword1 (str : string list) wrd =
let temp, wrd, count = countword2 str wrd ([], 0) in
temp, wrd, count

let rec public countword (str : string list) =
match str with
| [] -> []
| h::_ ->
  let temp, wrd, count = countword1 str h in
       [(wrd, count)] @ countword temp
4

3 に答える 3

16

パッドのバージョンでさえ、より効率的で簡潔にすることができます。

let countWords = Seq.countBy id

例:

countWords ["a"; "a"; "b"; "c"] //returns: seq [("a", 2); ("b", 1); ("c", 1)]
于 2012-03-07T21:37:59.483 に答える
7

文字列リスト内の単語の頻度をカウントしたい場合、あなたのアプローチはやり過ぎのようです。Seq.groupByこの目的に適しています:

let public countWords (words: string list) = 
   words |> Seq.groupBy id
         |> Seq.map (fun (word, sq) -> word, Seq.length sq)
         |> Seq.toList
于 2012-03-07T21:18:07.833 に答える
2

ソリューションは、新しい単語が見つかるたびに、入力リストを数回繰り返します。それを行う代わりに、リストを1回だけ繰り返して、すべての単語のすべての出現回数を保持する辞書を作成することができます。

これを機能的なスタイルで行うMapには、不変の辞書であるF#を使用できます。

let countWords words = 
  // Increment the number of occurrences of 'word' in the map 'counts'
  // If it isn't already in the dictionary, add it with count 1
  let increment counts word =
    match Map.tryFind word counts with
    | Some count -> Map.add word (count + 1) counts
    | _ -> Map.add word 1 counts

  // Start with an empty map and call 'increment' 
  // to add all words to the dictionary
  words |> List.fold increment Map.empty

同じことを命令型スタイルで実装することもできます。これは、より効率的ですが、エレガントではありません(そして、機能的なスタイルのすべての利点を得るわけではありません)。ただし、標準のミュータブルDictionaryはF#からもうまく使用できます(これはC#バージョンに似ているため、ここでは記述しません)。

最後に、標準のF#関数のみを使用した単純なソリューションが必要な場合はSeq.groupBy、padで提案されているように使用できます。Dictionaryこれはおそらくベースバージョンとほぼ同じくらい効率的です。ただし、F#を学習しているだけの場合countWordsは、自分のような再帰関数をいくつか作成することを学ぶのに最適な方法です。

あなたのコードについていくつかのコメントを与えるために-あなたのアプローチの複雑さは少し高いですが、それはおそらく問題ないはずです。ただし、いくつかの一般的な問題があります。

  • あなたのcountword2関数には、がありますif h = wrd then ... else last @ [h], countlast @ [h]リスト全体のクローンを作成する必要があるため、この呼び出しは非効率的lastです。これの代わりにh::last、順序は重要ではないので、単語を先頭に追加するように書くことができます。

  • 最後の行では、で@再び使用してい[(wrd, count)] @ countword tempます。これは必要ありません。リストの先頭に単一の要素を追加する場合は、次を使用する必要があります(wrd,count)::(countword temp)

于 2012-03-07T21:18:49.900 に答える