在Haskell中旋转列表

cod*_*kid 23 haskell

我有一个列表a,

let a = ["#","@","#","#"]
Run Code Online (Sandbox Code Playgroud)

如何旋转这@两个空格,以便它最终像这样?

["#","#","#","@"]
Run Code Online (Sandbox Code Playgroud)

我认为这可行,

map last init a
Run Code Online (Sandbox Code Playgroud)

但也许语法必须不同,因为map只能用于一个函数?

dav*_*420 62

为了完整起见,一个适用于空列表和无限列表的版本.

rotate :: Int -> [a] -> [a]
rotate _ [] = []
rotate n xs = zipWith const (drop n (cycle xs)) xs
Run Code Online (Sandbox Code Playgroud)

然后

Prelude> rotate 2 [1..5]
[3,4,5,1,2]
Run Code Online (Sandbox Code Playgroud)

  • 最好的解决方案,imho.非常_haskellish_. (7认同)
  • `zipWith const`是天才.我偷了那个. (6认同)
  • @tel关于`zipWith const`的一种思考方式是[`ZipList`]的`<*`(http://www.haskell.org/ghc/docs/latest/html/libraries/base-4.6.0.1 /Control-Applicative.html#t:ZipList). (6认同)
  • 该解决方案面临大整数输入的问题。尝试旋转 9999999999 [1, 2, 3] ,需要相当长的时间才能返回。由于该函数必须处理至少“length xs”数据点,因此应该考虑计算长度并删除“mod n(length xs)”,而不是删除前面的n个元素,这是O(n)并且n可以很大。 (2认同)

MGw*_*nne 25

使用该cycle函数的简单解决方案,它创建输入列表的无限重复:

rotate :: Int -> [a] -> [a]
rotate n xs = take (length xs) (drop n (cycle xs))
Run Code Online (Sandbox Code Playgroud)

然后

> rotate 2 ["#","@","#","#"]
["#","#","#","@"].
Run Code Online (Sandbox Code Playgroud)

  • 或者用较少的parens,`take(长度xs).掉落 循环$ xs` (6认同)

aug*_*tss 17

为什么让它变得复杂?

rotate n xs = bs ++ as where (as, bs) = splitAt n xs
Run Code Online (Sandbox Code Playgroud)

  • 但是,与其他答案不同,这不允许旋转超过列表的长度. (2认同)

azt*_*tek 14

rotate :: Int -> [a] -> [a]
rotate  =  drop <> take
Run Code Online (Sandbox Code Playgroud)

因为instance Monoid b => Monoid (a -> b)上面的例子相当于

rotate n  =  drop n <> take n
Run Code Online (Sandbox Code Playgroud)

这又相当于

rotate n xs  =  drop n xs <> take n xs
Run Code Online (Sandbox Code Playgroud)

因为instance Monoid d => Monoid (c -> d)实例,它等价于

rotate n xs  =  drop n xs ++ take n xs
Run Code Online (Sandbox Code Playgroud)

因为instance Monoid [e]实例(带有b ~ c -> dd ~ [e])。

(好吧,Semigroup已经足够了,但这里是一样的)。


Wol*_*olf 5

我是Haskell的新手,所以MGwynne的答案很容易理解。结合建议使用另一种语法注释,我试图使其在两个方向上都能正常工作。

rotate :: Int -> [a] -> [a]
rotate n xs = take lxs . drop (n `mod` lxs) . cycle $ xs where lxs = length xs
Run Code Online (Sandbox Code Playgroud)

因此rotate (-1) [1,2,3,4],您得到的结果与相同rotate 3 [1,2,3,4]

我以为我必须添加它,因为dropping少于0个元素不会执行任何操作,因此我的首选答案给出了带有错误负值的“错误”(至少令人困惑)结果n

此解决方案的有趣之处在于,它结合了负旋转的“完整性”和对空列表的处理。感谢Haskell的懒惰,它也为给出了正确的结果rotate 0 []