さまざまな組み込み関数を使用することができますし、動作を再構築するための変換特別な関数を最初から構築するための再帰に関する基本的な知識を持つことも良いことです。
また、より大きな問題を解決する方法を学ぶために、問題をより小さな問題に分割することを学ぶために、再帰でこれを行うことをお勧めします。
あなたは再帰的な方法で考えるならば、あなたはTODOが必要なもの:
- あなたは一つの要素を取得するために、リストの先頭を削除します。
- 次に、キーと指定したキーのすべての値を含むタプルを作成します。
- 処理した現在のキーですべての要素を削除し、このリストで繰り返します。
- 入力リストが空の場合、出力も空です。
だから、で始まる:
let rec group list =
if List.isEmpty list then []
else
???
あなたはList.head
と、リストの最初の要素を削除します。しかし、我々はまた、 の2つのコンポーネントにタプルを抽出したい。これを達成する
let k,v = List.head list
私たちが作成したいのは、同じキーを持つ新しいタプルですが、入力リストのすべての値です。まだ関数はありませんが、キーとリストを渡すことができる関数valuesOf
があると仮定し、定義されたキーのすべての値を返します。あなたは私たちがk
として2
を持っているでしょうし、私たちはvaluesOf 2 list
戻り["b";"c"]
を想定して定義された入力リストの最初の繰り返しで
(k, (valuesOf k list))
。
したがって、上記のコードは値として(2, ["b";"c"])
を返します。今再帰呼び出し。キーとリストを渡すことができる関数removeKey
があると仮定し、指定されたキーのすべての要素が削除された新しいリストを返します。唯一
(group (removeKey k list))
あなたは:例として
(removeKey k list)
removeKey 2 [(1,"a");(2,"a");(2,"b");(3,"a")]
はremoveKey
リターンはあなたが上で再発する必要がある1つであることを
[(1,"a");(3,"a")]
この新しいリストを返す必要がありますボットを入れなければならないh個まとめて。戻りたいものは、再帰的な結果を持つ新しいタプルです。
(k, (valuesOf k list)) :: (group (removeKey k list))
と1つの機能として。
let rec group list =
if List.isEmpty list then []
else
let k,v = List.head list
(k, (valuesOf k list)) :: group (removeKey k list)
我々はまだ行われていない、我々はまだvaluesOf
とremoveKey
を作成する必要があります。
let rec valuesOf key list =
match list with
| [] -> []
| x::list ->
let k,v = x
if k = key
then v :: (valuesOf key list)
else (valuesOf key list)
valuesOf
代わりList.head
またはList.tail
を使用しての、リストを分解するためにパターンマッチングを使用しています。要素が指定されたキーを持っているかどうかを確認するだけです。それが残っている場合は、残りのリストと連結した現在の値を返します。それ以外の場合は、再帰呼び出しの結果を返し、現在の値を削除します。
removeKey
も同様です。タプルのキーが一致しているかどうかをチェックし、そうであれば要素全体を削除し、再帰呼び出しを返します。それ以外の場合は、再帰呼び出しで現在の要素を返します。
let rec removeKey key list =
match list with
| [] -> []
| x::list ->
let k,v = x
if k = key
then (removeKey key list)
else x :: (removeKey key list)
となっています。一気にすべて
let rec valuesOf key list =
match list with
| [] -> []
| x::list ->
let k,v = x
if k = key
then v :: (valuesOf key list)
else (valuesOf key list)
let rec removeKey key list =
match list with
| [] -> []
| x::list ->
let k,v = x
if k = key
then (removeKey key list)
else x :: (removeKey key list)
let rec group list =
if List.isEmpty list then []
else
let k,v = List.head list
(k, (valuesOf k list)) :: group (removeKey k list)
group [(2,"c");(1,"a");(2,"b");(2,"d");(3,"a");(1,"b")]
// returns: [(2, ["c"; "b"; "d"]); (1, ["a"; "b"]); (3, ["a"])]
上記の関数はtail-recursiveではありません。しかしvaluesOf
とremoveKey
をList.fold
またはList.foldBack
で簡単に書き直すことができます。ここでは、要素の順序が変わるかどうかは問題ではないと仮定して、List.fold
を使用します。我々は全体のリストにアクセスする必要があるため
let valuesOf key list =
List.fold (fun acc (k,v) ->
if k = key
then v :: acc
else acc
) [] list
let removeKey key list =
List.fold (fun acc (k,v) ->
if k = key
then acc
else (k,v) :: acc
) [] list
group
は簡単List.fold
またはList.foldBack
で書き換えができません。しかし、テール再帰を達成することはまだ難しいことではありません。
let group list =
let rec loop result list =
if List.isEmpty list then result
else
let k,v = List.head list
loop
((k, (valuesOf k list)) :: result)
(removeKey k list)
loop [] list
何千ものキーと値のペアを持つリストがない場合は、非テール再帰関数を保持することもできます。それはあなた自身再帰関数のような種類を作成することができるはずList.groupBy
とList.map
のように、既に提供された機能を持つ小さなコードを作成するために、良い感じている場合でも
。どうして?
不変リンクリストは再帰的に定義されたデータ構造であり、再帰的関数を扱うのは当然のことです。このような関数を自分で作成する方法がわからない場合は、独自の再帰的なデータ構造を作成する瞬間に問題が発生します。既に使用できるgroupBy
とmap
のような事前定義済み関数はゼロです。これらの機能を自分で構築する必要があります。
List
モジュールに定義されている機能を再構築しようとしたり、ここに記載されているようなことは、実際に自分で行うべき訓練の良い方法です。
'Seq.groupBy'は私が思っている通りです(または少なくとも難しい部分) –
既に(List.groupBy')それが悪化しています。それが適切にグループ化されている間、各値にはキーも含まれます。 '[(2、[(2、" c ");(2、" b ")]); (1、[(1、 "a")])] –