F#函数查找列表的所有旋转

时间:2014-03-21 00:07:19

标签: list recursion f# rotation

我在这里有一些F#代码用于递归函数,它将列表向左旋转n个位置。我是F#的新手,我正在寻找一种修改此代码的方法,不仅可以通过n位置输出一次旋转,还可以输出所有可能的旋转。

例如,假设我有清单:

let list1 = [1; 2; 3; 4]

我想在此列表上调用rotate,以便输出为:

[ [1; 2; 3; 4]; [2; 3; 4; 1]; [3; 4; 1; 2]; [4; 1; 2; 3] ]

我所做的左移n的代码是:

let rec rotate xs k = 
    match xs, k with
        |[], _ -> []
        |xs, 0 -> xs
        |x::xs, k when k > 0 -> rotate(xs @ [x])(k-1)
        |xs, k -> rotate xs (List.length xs + k)

我不知道如何编辑它来执行上面列出的步骤。任何帮助或资源将不胜感激。我应该补充一点,我真的希望函数是递归的。感谢。

4 个答案:

答案 0 :(得分:7)

如果我正确理解了这个问题,你也可以使用内置的List.permute函数编写函数:

let rotate xs =
    let length = xs |> List.length
    let perm n = xs |> List.permute (fun index -> (index + n) % length) 
    [1 .. length] |> List.rev |> List.map perm

示例输出(稍微格式化以提高可读性):

> [1 .. 4] |> rotate;;
val it : int list list =
  [[1; 2; 3; 4];
   [2; 3; 4; 1];
   [3; 4; 1; 2];
   [4; 1; 2; 3]]

答案 1 :(得分:2)

我会从原始列表中创建无限循环序列开始。然后使用List.init获取所有轮换。

let rotations list = 
    let rec cyclic sequence = seq {
        yield! sequence
        yield! cyclic sequence }
    let cyclic = cyclic list
    let length = List.length list
    List.init length (fun i -> cyclic |> Seq.skip i |> Seq.take length |> List.ofSeq)

重要的是,序列是懒惰的,因此可以无限。

答案 2 :(得分:1)

使用您已编写的rotate函数:

let rotations xs = List.init (List.length xs) (rotate xs) 

顺便说一下,您可以将rotate功能缩短为:

let rec rotate xs k = 
    match xs, k with
        |[], _ -> []
        |xs, 0 -> xs
        |x::xs, k -> rotate (xs @ [x]) (k-1)

模式自上而下匹配,因此保护when k > 0不是必需的。原始解决方案的最后一行永远不会匹配,所以我删除了它。

答案 3 :(得分:0)

由于我想使用递归和匹配来完成这个特定的问题,我设法弄清楚了,这就是我提出的:

let rotate xs =
    let n = List.length xs
    let rec rotation xs n = 
        match xs, n with
        |[], _ -> []
        |xs, 0 -> xs
        |x::xs, n -> rotation (xs @ [x]) (n-1)

    let rec rotateList xs n = //we are compiling a list of different rotations
        match xs, n with
        |xs, 0 -> [] 
        |xs, n -> (rotation xs ((List.length xs)-n))::rotateList xs (n-1)
    rotateList xs n 

我还特别想要一个输入参数,即列表