4

整数配列を次の擬似パターンと照合したいと思います。ここで、aはこれらの数値が等しいか0である(つまり、任意の数値が0に等しいと仮定する)ことを意味します。

[| a; a; a; a; a; |]          // matches [| 1; 1; 0; 0; 1 |]
[| a; a; a; not a; a; |]      // matches [| 3; 3; 0; 2; 3 |]
[| a; a; not a; a; a; |]      // matches [| 4; 4; 2; 0; 4 |]
[| a; not a; a; a; not a; |]  // matches [| 1; 2; 0; 0; 3 |]
[| a; a; a; not a; a; |]      // matches [| 1; 1; 0; 4; 1 |]
[| not a; a; a; a; a; |]      // matches [| 5; 1; 0; 1; 1 |]

どうすればよいですか?

4

3 に答える 3

5

あなたの例では、配列の最初の要素は常にaブール配列で一致できることです。

match Array.map (fun x -> x = Array.get arr 0 || x = 0) arr with
| [| true; true; true; true; true; |] -> ... // matches [| 1; 1; 0; 0; 1 |]
| [| true; true; true; false; true; |] -> ... // matches [| 3; 3; 0; 2; 3 |]
| [| true; true; false; true; true; |] -> ... // matches [| 4; 4; 2; 0; 4 |]
| [| true; false; true; true; false; |] -> ... // matches [| 1; 2; 0; 0; 3 |]
| [| true; true; true; false; true; |] -> ... // matches [| 1; 1; 0; 4; 1 |]
| _ -> ...

これにより一時的な配列が作成されますが、小さいサイズの配列では大した問題ではありません。

アップデート:

最初aの列が別の列にある場合は、その列に投影して別のパターンマッチングを実行します(5列に対して最大5つの一致があります)。

match Array.map (fun x -> x = Array.get arr 1 || x = 0) arr with
| [| false; true; true; true; true; |] -> ... // matches [| 5; 1; 0; 1; 1 |]
| ...

とはいえ、疑似パターンの数と複雑さが増すと、パターンマッチングの代わりに関数を使用する方がよいでしょう。

于 2012-12-14T12:49:49.030 に答える
2

検出するパターンによってパラメーター化されたアクティブなパターンを定義できます。この例では、またはのいずれかを含む配列を使用した疑似構文を使用してこれらのパターンを記述しますが、入力に一致する値を含める場合は、同じ値を含む実際の配列として簡単に記述できます。たとえば、次のようになります。anot a

[| 'a'; 'a'; 'b'; 'a'; 'a'; |]

@bytebusterのソリューションのように文字列にすることもできます(メソッドstringchar[]使用して変換できますToCharArray)。次に、アクティブなパターンを定義できます。

let inline (|ArrayPattern|_|) pattern input =
  let matches =
    Array.zip pattern input
    |> Seq.groupBy fst 
    |> Seq.forall (fun (_, values) -> 
        let cases = values |> Seq.map snd |> set
        Set.count (cases - Set.singleton 0) <= 1)
  if matches then Some() else None  

これは、@bytebusterが実装するものと本質的に同じだと思います。ここでは、入力配列の要素をパターン内の対応するキーでグループ化し、set操作を使用して、各グループにゼロ以外の値が最大で1つあることを確認します。

これを使用するために、配列パラメーターが探している特定のパターンを指定する場所とint[]照合できるようになりました。ArrayPattern [| ... |]

match [| 1; 1; 2; 0; 1 |] with 
| ArrayPattern [| 'a'; 'a'; 'b'; 'a'; 'a'; |] -> printfn "match"
| _ -> printfn "not"
于 2012-12-14T22:13:26.537 に答える
1

単なる計算作業なので、あまり美しく見えないのではないかと思います。それにもかかわらず、これが私の試みです。string読みやすくするために、「a」と「nota」にaを使用したことに注意してください。

// Define possible return values
type TriState<'T> = | Yes of 'T | No of 'T | Unknown with 
    override this.ToString() =
        match this with
        | Unknown   -> "Unknown"
        | Yes value -> sprintf "Array matches, common value %A" value
        | No value  -> sprintf "Array mismatches, common value %A" value

// a boilerplate function
let matchA (pat: string) xs =
    let mustBeA, mustNotBeA =
        List.zip
            (xs |> Array.toList)
            (pat.ToCharArray() |> Array.toList)
        |> List.partition (snd >> ( (=) 'A'))
    // these values must be all equal
    let mustBeA' =
        mustBeA |> List.map fst |> List.filter ( (<>) 0)
    // these values must NOT be equal to the value taken from above
    let mustNotBeA' =
        mustNotBeA |> List.map fst
    match mustBeA' with
    | []            -> Unknown   // can't find the "must" value
                                 // due all "must" values are zero
    | mustValue::_  ->           // we have bootstrap value to compare against
        if (List.forall ( (=) mustValue) mustBeA')
            && (List.forall ( (<>) mustValue) mustNotBeA')
        then Yes mustValue
        else No mustValue

今、テストします:

[| 1; 2; 0; 0; 3 |] |> matchA "ABAAB" |> printf "%A\n" // Yes 1
[| 4; 4; 2; 0; 4 |] |> matchA "AABAA" |> printf "%A\n" // Yes 4
[| 5; 1; 0; 1; 1 |] |> matchA "BAAAA" |> printf "%A\n" // Yes 1

もちろん、パラメータ化されたアクティブパターンにラップすることもできます。

let (|MatchesA|_|) pattern arr =
    matchA pattern arr |> function | Yes x -> Some x | _ -> None

match [| 1; 2; 0; 0; 3 |] with
| MatchesA ("AAAAB") x -> sprintf "Pattern1 %d" x
| MatchesA ("ABAAB") x -> sprintf "Pattern2 %d" x
| _                    -> "Unknown"
|> printf "%A\n"
于 2012-12-14T16:55:08.393 に答える