需要将F#命令式代码转换为功能性的想法

Ale*_*lex 0 f# functional-programming imperative

我有一个功能女巫是以命令式的方式编写的,无法理解如何将其转换为更强大的功能方法.

该函数接受一系列字符串并返回一个seq的元组,其中每个元组由输入中的2,7,12,...和5,10,15,...项组成.

例:

输入= {"Lorem","ipsum","dolor","set","amet","consectetuer","adipiscing","elit","Aenean","commodo","ligula","eget" ,"dolor","Aenean","massa"}

Ouput = {("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
    }
Run Code Online (Sandbox Code Playgroud)

任何有关起点的帮助或提示都表示赞赏.

Tom*_*cek 6

我不完全理解你想要的行为 - 生成你想要配对的索引的算法是什么?无论如何,一个不错的功能解决方案是将您想要分别配对的元素然后使用它们进行组合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))
Run Code Online (Sandbox Code Playgroud)

我使用你的数字-1,因为索引是0 - 所以上面给出了你想要的结果.第二个系列看起来像是5的倍数,所以也许你想要i%5 = 4生成第二个元素:

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))
Run Code Online (Sandbox Code Playgroud)

我仍然没有看到生成第一个元素的一般机制!

编辑还有一个想法 - 是第一个生成的序列i*5 + 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))
Run Code Online (Sandbox Code Playgroud)

...或者如果你想让代码更加轻松,你可以重构:

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)
Run Code Online (Sandbox Code Playgroud)