获取F#集合中两个元素之间的元素

时间:2016-02-14 16:00:18

标签: f#

我想要一个List或Array,并在集合中给出两个元素,获取它们之间的所有元素。但我希望以循环的方式做到这一点,例如给定一个列表[1;2;3;4;5;6],如果我要求介于4和2之间的元素,我会回来[5;6;1]

习惯于命令式编程我可以很容易地用循环来做这件事,但我想在F#中可能有一个更好的习惯方法。

修改

这是我提出的一种方法,找到了Array.indexed函数

let elementsBetween (first:int) (second:int) (elements: array<'T>) =
    let diff = second - first
    elements 
    |> Array.indexed
    |> Array.filter (fun (index,element) -> if diff = 0 then false
                                            else if diff > 0 then index > first && index < second
                                            else if diff < 0 then index > first || index < second
                                            else false

这种方法只适用于数组,但这似乎相当不错。我有一种感觉,我可以通过用模式匹配替换if / then / else来清理它,但我不确定如何干净地做到这一点。

3 个答案:

答案 0 :(得分:2)

我没有使用f#编译器在我的普通计算机上,所以我还没有测试过它。它应该看起来像这样

[编辑]感谢@FoggyFinder向我展示https://dotnetfiddle.net/。我现在用它来测试下面的代码。

[编辑]这应该在一次通过中找到圆形范围。

let x = [1;2;3;4;5]
let findCircRange l first second =
    let rec findUpTo (l':int list) f (s:int) : (int list * int list) = 
        match l' with 
        | i::tail -> 
            if i = s then tail, (f [])
            else findUpTo tail (fun acc -> f (i::acc)) s
        // In case we are passed an empty list.
        | _ -> [], (f [])
    let remainder, upToStart = findUpTo l id first
    // concatenate the list after start with the list before start. 
    let newBuffer = remainder@upToStart
    snd <| findUpTo newBuffer id second

let values = findCircRange x 4 2
printf "%A" values

findUpTo获取一个列表(l&#39;),一个用于创建余数列表(f)的函数和一个要查找的值。我们通过它递归(尾递归)来找到给定值的列表和给定值之后的列表。通过将结尾附加到剩余部分来包裹缓冲区。再次将它传递给findUpTo以找到最后。将缓冲区返回到最后。

我们传递一个累积找到的项目的函数。这种技术允许我们在函数调用unwind时附加到列表的末尾。

当然,这里没有错误检查。我们假设开始和结束确实存在。这将留给读者练习。

答案 1 :(得分:2)

您应该查看MSDN,Collections.Seq模块。

让我们试着变得聪明:

let elementsBetween a e1 e2 =
    let aa = a |> Seq.append a
    let i1 = aa |> Seq.findIndex (fun e -> e = e1)
    let i2 = aa |> Seq.skip i1 |> Seq.findIndex (fun e -> e = e2)
    aa |> Seq.skip(i1+1) |> Seq.take(i2-1)

答案 2 :(得分:0)

这是使用你的diff与列表和列表切片的想法的变体 <some list.[x .. y]

let between (first : int) (second : int) (l : 'a list) : 'a list =
    if first < 0 then
        failwith "first cannot be less than zero"
    if second < 0 then
        failwith "second cannot be less than zero"
    if first > (l.Length * 2) then
        failwith "first cannot be greater than length of list times 2"
    if second > (l.Length * 2) then
        failwith "second cannot be greater than length of list times 2"

    let diff = second - first
    match diff with
    | 0 -> []
    | _ when diff > 0 && (abs diff) < l.Length -> l.[(first + 1) .. (second - 1)]
    | _ when diff > 0 -> (l@l).[(first + 1) .. (second - 1)]
    | _ when diff < 0 && (abs diff) < l.Length -> l.[(second + 1)  .. (second + first - 1)]
    | _ when diff < 0 -> (l@l).[(second + 1)  .. (second + first - 1)]