0

[(String1, exp1); という形式のリストを生成する関数があります。(文字列 2、exp2); ...など]

exp は、以前に定義した型です。

そのようなリストが無効かどうかを判断する方法が必要です。繰り返し文字列があり、それぞれに異なる exp がペアになっている場合、リストは無効です。すなわち:

[("y", exp1); ("y", exp2); ("x", exp3)]   //Invalid, as "y" is repeated with different exps

[("y", exp1); ("y", exp1); ("x", exp3)]   //Valid, as "y" is repeated with the same exps

これに対する適切な解決策を探し、パターン マッチングを使用してみましたが、うまくいきませんでした。私が見逃しているこれに対する簡単な解決策はありますか?ありがとう!

4

3 に答える 3

4

簡単な解決策は、groupByを使用することです:

let hasNoRepeatedComponents xs =
   xs        
   |> Seq.groupBy fst
   |> Seq.map snd
   |> Seq.forall (fun s -> Set.count (Set.ofSeq s) = 1)

繰り返されるコンポーネントが連続していると仮定しない限り、パターン マッチングはあまり役に立ちません。

于 2013-10-01T07:17:55.413 に答える
2

パターン マッチを行う場合は、前に見た項目を格納するための何らかの構造が必要です。ルックアップを行う必要があるため、マップはこれに役立ちます。パターンマッチのアプローチは次のとおりです。

let isValid source = 
  let rec loop source (m : Map<_,_>) =
    match source with
    | [] -> (true, "")
    | (s,e) :: xs -> 
        match m.TryFind s with
        |  Some v when v <> e -> (false, sprintf "Key %s is repeated with different expressions" s)
        |  Some v -> loop xs m
        |  _ -> loop xs (m.Add (s,e))
  loop source Map.empty

パッドのソリューションは非常にエレガントです。ただし、最初に無効な反復項目が検出された時点で停止するため、平均的な無効なケースでは少し速くなります。

于 2013-10-01T07:39:05.783 に答える
1

@padの回答は良い出発点ですが、必要に応じて機能しませんでした(つまり、最後のサンプルが正しく機能しません)。

問題を正しく理解していれば、連続していない重複は依然として重複と見なされるため、リストが「無効」になります。

基本的に、groupBy2 つの長さを比較する必要がある場合:

  • 「y」、「x」などに関連付けられたシーケンス要素の元の長さ。
  • を適用して から作成されたシーケンスの長さSeq.distinct

コードは次のとおりです。

let isValid xs =
    xs
    |> Seq.groupBy fst
    |> Seq.map snd  // we no longer need the key
    // compare two lengthes: original and filtered/distinct
    |> Seq.forall (fun x -> (Seq.length x) = Seq.length(Seq.distinct x))

[("y", 5); ("y", 6); ("x", 7)] |> isValid |> printfn "%A" // true
[("y", 5); ("y", 5); ("x", 7)] |> isValid |> printfn "%A" // false
[("y", 5); ("y", 6); ("x", 7); ("y", 7); ("y", 6)] |> isValid |> printfn "%A" // false
于 2013-10-01T21:56:36.433 に答える