【问题标题】:F# function to find all rotations of a listF#函数查找列表的所有旋转
【发布时间】:2014-04-28 04:01:59
【问题描述】:

我这里有一些 F# 代码,用于将列表向左旋转n 个位置的递归函数。我对 F# 非常陌生,我正在寻找一种方法来修改此代码以输出不只是按n 位置的一个旋转,而是所有可能的旋转。

例如,假设我有列表:

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

我想在这个列表上调用旋转,这样输出是:

[ [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)

我不确定如何编辑它来执行上面列出的步骤。任何帮助或资源将不胜感激。我应该补充一点,我真的想要递归。谢谢。

【问题讨论】:

    标签: list recursion f# rotation


    【解决方案1】:

    因为我想使用递归和匹配来解决这个特定问题,所以我设法弄清楚了,这就是我想出的:

    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 
    

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

    【讨论】:

      【解决方案2】:

      如果我对问题的理解正确,您也可以使用内置的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]]
      

      【讨论】:

      • 我真的很喜欢这个解决方案,谢谢,我唯一的问题是我正在寻找一个特别的递归函数,但这肯定有助于我的理解。
      【解决方案3】:

      使用您已经编写的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 不是必需的。您原始解决方案的最后一行永远不会匹配,因此我将其删除。

      【讨论】:

      • 尾递归,开机!
      • 顺便说一句,最好将参数的顺序颠倒,所以列表是结束参数,用于部分应用程序。此外,如果您在k % List.length xs 上匹配而不是k,然后在匹配的最后一个子句中执行rotate (xs @ [x]) ((k % List.length xs) - 1),您可以为您的机器节省大量冗余工作......
      【解决方案4】:

      我将从您的原始列表中创建一个无限循环序列开始。然后使用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)
      

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

      【讨论】:

        猜你喜欢
        • 2015-10-31
        • 1970-01-01
        • 1970-01-01
        • 2020-01-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多