0

私は関数魔女が命令型のスタイルで書かれており、それをより堅牢な関数型アプローチに変換する方法について頭を悩ませています。

この関数は一連の文字列を受け取り、各タプルが入力からの 2,7,12,.. および 5,10,15,.. 項目で構成される一連のタプルを返します。

例:

入力 = { "Lorem", "ipsum", "dolor", "set", "amet", "consectetuer", "adipiscing", "elit", "Aenean", "commodo", "ligula", "eget" 、「ドロール」、「アエネアン」、「マッサ」}

出力 = { ("ipsum", "amet"), ("adipiscing", "commodo"), ("eget", "massa") }

let convert (input : seq<string>) : seq<(string * string)> =
    let enum = input.GetEnumerator()
    let index = ref 0
    let first = ref ""
    let second = ref ""

    seq {
        while enum.MoveNext() do
            let modIndex = !index % 5
            index := !index + 1

            if (modIndex % 2 = 0 && !first = "") then first := enum.Current
            if (modIndex % 5 = 0 && !second = "") then second := enum.Current

            if modIndex = 0  then
                let result = (!first, !second)
                first := ""
                second := ""
                yield result
    }

出発点の助けやヒントをいただければ幸いです。

4

3 に答える 3

6

私はあなたが望む振る舞いを完全には理解していません-あなたがペアにしたいインデックスを生成するためのアルゴリズムは何ですか?とにかく、1つの優れた機能ソリューションは、ペアリングする要素を個別に取得し、を使用してそれらを結合することSeq.zipです。

を使用Seq.mapiして値にインデックスを追加してから、を使用Seq.chooseして正しいインデックスの値を取得できます(他のすべての値をスキップします)。ハードコードされたインデックスの場合、次のように記述できます。

let indexed = input |> Seq.mapi (fun i s -> i, s)
Seq.zip 
  (indexed |> Seq.choose (fun (i, v) -> if i=1 || i=6 || i=11 then Some v else None))
  (indexed |> Seq.choose (fun (i, v) -> if i=4 || i=9 || i=14 then Some v else None))

インデックスが0からのものであるため、私はあなたの数値-1を使用しました-したがって、上記はあなたが望む結果を与えます。i%5 = 42番目のシリーズは5の倍数のように見えるので、おそらく2番目の要素を生成したいとします。

let indexed = input |> Seq.mapi (fun i s -> i, s)
Seq.zip 
  (indexed |> Seq.choose (fun (i, v) -> if i=1 || i=6 || i=11 then Some v else None))
  (indexed |> Seq.choose (fun (i, v) -> if i%5 = 4 then Some v else None))

ただし、最初の要素を生成するための一般的なメカニズムはまだわかりません。

編集もう1つのアイデア-最初のシーケンスはによって生成されi*5 + 2、2番目のシーケンスはi*5?によって生成されます。その場合、あなたの例は間違っていますが、次のように書くことができます:

let indexed = input |> Seq.mapi (fun i s -> i, s)
Seq.zip 
  (indexed |> Seq.choose (fun (i, v) -> if i%5 = 2 then Some v else None))
  (indexed |> Seq.choose (fun (i, v) -> if i%5 = 0 then Some v else None))

...または、コードをシュロッターにしたい場合は、リファクタリングできます。

let filterNthElements div rem = 
  input |> Seq.mapi (fun i s -> i, s)
        |> Seq.choose (fun (i, v) -> if i%div = rem then Some v else None)

Seq.zip (filterNthElements 5 2) (filterNthElements 5 0)
于 2012-07-01T21:27:06.363 に答える
0

私は f# ではなく haskell から来たので、おそらく無効な f# コードのアイデアを提供します。

最初に、入力から 2 つのリストを生成します。

let zeromod5 = filter (index == 0 % 5) input
let twomod5 = filter (index == 2 % 5) input

リストになるはずです

{ "ipsum", "adipiscing","eget"}
{ "amet", "commodo","massa" }

次に、それらを圧縮します。つまり、次のような方法でペアのリストを作成します

zip zeromod5 twomod5

編集:

Haskell バージョン:

zipWeird :: [String] -> [(String, String)]
zipWeird ss = zip twoMod5s zeroMod5s
            where zeroMod5s = map fst $ filter (\(_,y) -> y `mod` 5 == 0) eSS
                  twoMod5s = map fst $ filter (\(_,y) -> y `mod` 5 == 2) eSS
                  eSS = zip ss [1..]

zipWeird2 :: [String] -> [(String, String)]
zipWeird2 ss = map fst $ filter (\(_,y) -> y `mod`5 ==1) ezSS
             where zSS = zip (tail ss) (drop 4 ss)
                   ezSS = zip zSS [1..]

input :: [String]
input = words ("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, "++
              "sed diam nonumy eirmod tempor invidunt ut labore et dolore "++
              "magna aliquyam erat, sed diam voluptua. At vero eos et "++
              "accusam et justo duo dolores et ea rebum. Stet clita kasd "++
              "gubergren, no sea takimata sanctus est Lorem ipsum dolor sit "++
              "amet.")

main :: IO ()
main = do 
          print $ zipWeird input
          print $ zipWeird2 input
于 2012-07-01T21:34:08.067 に答える