【问题标题】:Splitting a list into parts then shuffling those parts: Haskell将列表拆分为多个部分,然后对这些部分进行改组:Haskell
【发布时间】:2018-07-18 04:27:38
【问题描述】:

问题是:定义一个函数shuffle :: Int -> [a] -> [a],它接受一个 自然数 n 和一个偶数长度的列表,然后将列表拆分并重新排列 n 次。例如,shuffle 2 [1,2,3,4,5,6] = [1,5,4,3,2,6]。我有一个相应的函数 riffle,但我不知道如何拆分列表。

我的 riffle 函数是:

riffle :: [a] -> [a] -> [a]
riffle [] ys = ys
riffle xs [] = xs
riffle (x:xs)(y:ys) = x : y : riffle xs ys 

我开始洗牌,我想,这就是我所拥有的:

shuffle :: Int -> [a] -> [a]
shuffle [] = []
shuffle a xs = (length xs) 'div' a

我试图列出一个列表并将其分成指定为“a”的部分。我是 Haskell 的新手,仍然不确定它是如何工作的:感谢所有帮助。

【问题讨论】:

  • 假设我打电话给shuffle 2 [1,2,3,4,5,6],明天我用相同的输入再次调用它。你希望/期望结果是一样的吗?因为这就是 func prog / Haskell 的全部意义(当然还有更多)。
  • @Elmex80s 我希望输出是一样的,是的。
  • 拆分列表:Data.List.splitAt.

标签: list haskell recursion


【解决方案1】:

要将列表分成两半,并按顺序将两半分开,通常应使用龟兔算法。

-- split2 xs = splitAt (length xs `quot` 2) xs
split2 :: [a] -> ([a], [a])
split2 xs0 = go xs0 xs0
  where
    go (_:_:hs) (t:ts) =
      let (front, rear) = go hs ts
      in (t:front, rear)
    go _ ts = ([], ts)

这通常应该比计算列表的长度并除以二更有效。即使列表是无限的,它也可以工作。


但是,在这种情况下,您不需要惰性版本;您将立即使用下半部分。因此,如果您愿意,可以使用这个更 Lisp/Scheme/ML 风格的版本:

split2' :: [a] -> ([a], [a])
split2' xs0 = go [] xs0 xs0
  where
    go front (_:_:hs) (t:ts) = go (t:front) hs ts
    go front _ ts = (reverse front, ts)

我不确定哪个会更快,但split2' 不太容易受到编译器转换引入的空间泄漏的影响。

【讨论】:

    【解决方案2】:

    不是一个好的随机播放,你的第一个和最后一个元素永远不会移动。

    这样的?

    > let shuffle 0 x = x
          shuffle n x = shuffle (n-1) $ uncurry riffle $ splitAt (length x `div` 2) x
    

    或使用迭代

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-06-05
      • 2016-07-12
      • 2012-10-23
      • 2018-08-01
      • 2011-05-30
      • 1970-01-01
      • 2013-10-04
      相关资源
      最近更新 更多