1

これはおそらく些細なことであり、解決策はありますが、満足していません。どういうわけか、(はるかに) 単純なフォームは機能しないようで、角のケース (最初または最後に一致するペアのいずれか) が乱雑になります。

簡単にするために、一致ルールを2 の差がある 2 つ以上の数値として定義しましょう。例:

> filterTwins [1; 2; 4; 6; 8; 10; 15; 17]
val it : int list = [2; 4; 6; 8; 10; 15; 17]

私が現在使用しているコードは次のとおりです。

let filterTwins list =
    let func item acc =
        let prevItem, resultList = acc
        match prevItem, resultList with
        | 0, [] 
            -> item, []
        | var, [] when var - 2 = item
            -> item, item::var::resultList
        | var, hd::tl when var - 2 = item && hd <> var
            -> item, item::var::resultList
        | var, _ when var - 2 = item
            -> item, item::resultList
        | _ 
            -> item, resultList

    List.foldBack func list (0, [])
    |> snd

、大きなリスト、および並列プログラミング (うまくいきました)を実験する独自のオリジナルの演習を意図していList.foldBackましたが、「簡単な」部分を台無しにしてしまいました...

答えを導く

  • Daniel's last、113 文字*、わかりやすい、遅い
  • Kvbの2番目、106文字*(関数を含める場合)、簡単ですが、戻り値には作業が必要です
  • Stephen's 2nd、397 文字*、長くて比較的複雑ですが、最速です
  • Abel の155 文字* は、Daniel のものに基づいており、複製が可能で (これは必須ではありませんでした)、比較的高速です。

もっと多くの答えがありましたが、上記が最も明確だったと思います。ダニエルの答えを解決策として受け入れることで、誰かの気持ちを傷つけていないことを願っています。

※関数名は1文字としてカウント

4

5 に答える 5

2

これはあなたが望むことをしますか?

let filterTwins l = 
    let rec filter l acc flag =
        match l with
        | [] -> List.rev acc
        | a :: b :: rest when b - 2 = a -> 
            filter (b::rest) (if flag then b::acc else b::a::acc) true
        | _ :: t -> filter t acc false
    filter l [] false

これはひどく非効率的ですが、より多くの組み込み関数を使用する別のアプローチがあります。

let filterTwinsSimple l =
    l 
    |> Seq.pairwise 
    |> Seq.filter (fun (a, b) -> b - 2 = a)
    |> Seq.collect (fun (a, b) -> [a; b])
    |> Seq.distinct
    |> Seq.toList

多分少し良い:

let filterTwinsSimple l =
    seq { 
        for (a, b) in Seq.pairwise l do
            if b - 2 = a then 
                yield a
                yield b 
    }
    |> Seq.distinct
    |> Seq.toList
于 2011-02-23T21:21:55.203 に答える
1

これはどう?

let filterPairs f =
  let rec filter keepHead = function
  | x::(y::_ as xs) when f x y -> x::(filter true xs)
  | x::xs -> 
      let rest = filter false xs
      if keepHead then x::rest else rest
  | _ -> []
  filter false

let test = filterPairs (fun x y -> y - x = 2) [1; 2; 4; 6; 8; 10; 15; 17]

または、リストのすべてのアイテムが一意である場合は、次のようにすることができます。

let rec filterPairs f s =
  s
  |> Seq.windowed 2
  |> Seq.filter (fun [|a;b|] -> f a b)
  |> Seq.concat
  |> Seq.distinct

let test = filterPairs (fun x y -> y - x = 2) [1; 2; 4; 6; 8; 10; 15; 17]

編集

または、私がエレガントだと思う別の選択肢があります。最初に、リストを述語を満たす連続した項目のグループのリストに分割する関数を定義します。

let rec groupConsec f = function
| [] -> []
| x::(y::_ as xs) when f x y -> 
    let (gp::gps) = groupConsec f xs 
    (x::gp)::gps
| x::xs -> [x]::(groupConsec f xs)

次に、すべての結果をまとめて収集し、シングルトンを破棄して関数を構築します。

let filterPairs f =
  groupConsec f
  >> List.collect (function | [_] -> [] | l -> l)

let test = filterPairs (fun x y -> y - x = 2) [1; 2; 4; 6; 8; 10; 15; 17]
于 2011-02-23T21:39:31.053 に答える
1

次の解決策はあなた自身の精神にありますが、私はアルゴリズムの側面をカプセル化し、少し狂気に支配するために識別結合を使用します。

type status =
    | Keep of int
    | Skip of int
    | Tail

let filterTwins xl = 
    (Tail, [])
    |> List.foldBack
        (fun cur (prev, acc) ->
            match prev with
            | Skip(prev) when prev - cur = 2 -> (Keep(cur), cur::prev::acc)
            | Keep(prev) when prev - cur = 2 -> (Keep(cur), cur::acc)
            | _ -> (Skip(cur), acc))
        xl
    |> snd
于 2011-02-23T23:07:04.257 に答える
1

これは、私の他の答えと同様の識別結合戦略を使用する別のソリューションですが、シーケンスで遅延して動作するため、それらのツイン(素数?)が来るときにロールインするのを見ることができます:

type status =
    | KeepTwo of int * int
    | KeepOne of int
    | SkipOne of int
    | Head

let filterTwins xl = 
    let xl' =
        Seq.scan
            (fun prev cur ->
                match prev with
                | KeepTwo(_,prev) | KeepOne prev when cur - prev = 2 ->
                    KeepOne cur
                | SkipOne prev when cur - prev = 2 ->
                    KeepTwo(prev,cur)
                | _ ->
                    SkipOne cur)
            Head
            xl

    seq { 
        for x in xl' do
            match x with
            | KeepTwo(a,b) -> yield a; yield b
            | KeepOne b -> yield b
            | _ -> ()
    }
于 2011-02-24T02:07:54.817 に答える
0

完全を期すために、このスレッドの友好的な提案に基づいて、私が最終的に思いついたものでこれに答えます。

このアプローチの利点は、それが必要ないことSeq.distinctです。これは、重複を可能にするための改善であると私は信じています。ただし、それでも必要List.revであり、最速にはなりません。また、最も簡潔なコードでもありません(問題のソリューション自体の比較を参照してください)。

let filterTwins l = 
    l 
    |> Seq.pairwise 
    |> Seq.fold (fun a (x, y) -> 
        if y - x = 2 then (if List.head a = x then y::a else y::x::a) 
        else a) [0]
    |> List.rev 
    |> List.tail
于 2011-03-10T14:02:53.370 に答える