28

a定义了一个列表,

let a = ["#","@","#","#"]

我怎样才能旋转这@两个空间,让它像这样结束?

["#","#","#","@"]

我认为这可能有效,

map last init a

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

4

8 回答 8

66

为了完整起见,该版本适用于空列表和无限列表。

rotate :: Int -> [a] -> [a]
rotate _ [] = []
rotate n xs = zipWith const (drop n (cycle xs)) xs

然后

Prelude> rotate 2 [1..5]
[3,4,5,1,2]
于 2013-05-04T21:15:19.870 回答
26

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

rotate :: Int -> [a] -> [a]
rotate n xs = take (length xs) (drop n (cycle xs))

然后

> rotate 2 ["#","@","#","#"]
["#","#","#","@"].
于 2013-05-04T21:01:07.203 回答
19

为什么要复杂化?

rotate n xs = bs ++ as where (as, bs) = splitAt n xs
于 2013-05-04T22:18:04.433 回答
14
rotate :: Int -> [a] -> [a]
rotate  =  drop <> take

由于instance Monoid b => Monoid (a -> b)上面的实例等价于

rotate n  =  drop n <> take n

这又相当于

rotate n xs  =  drop n xs <> take n xs

因为instance Monoid d => Monoid (c -> d)实例,这相当于

rotate n xs  =  drop n xs ++ take n xs

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

(嗯,Semigroup就够了,但在这里也是一样的)。

于 2019-04-18T09:52:25.657 回答
9

我对haskell很陌生,所以MGwynne的回答很容易理解。结合建议替代语法的评论,我试图使它在两个方向上都起作用。

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

所以rotate (-1) [1,2,3,4]给你同样的结果rotate 3 [1,2,3,4]

我认为我必须添加这个,因为dropping 小于 0 的元素什么都不做,所以我的首选答案给出了n参数为负值的“错误”(至少令人困惑)结果。

这个解决方案的有趣之处在于它结合了负旋转的“完整性”和空列表的处理。由于 Haskell 的懒惰,它也为rotate 0 [].

于 2017-06-01T13:39:11.260 回答
3

初学者尝试:

myRotate :: Int -> [String] -> [String]
myRotate 0 xs = xs
myRotate n xs = myRotate (n-1) (last xs : init xs)
于 2013-05-05T03:27:11.863 回答
1

对于大型列表来说不是很快,但足够了:

rotate :: Int -> [a] -> [a]
rotate n xs = iterate rot xs !! n
  where
    rot xs = last xs : init xs

例如:

> rotate 2 ["#","@","#","#"]
["#","#","#","@"]
于 2013-05-04T20:52:19.340 回答
0
rotate :: Int -> [a] -> [a]
rotate n xs = drop k xs ++ take k xs
                where k = length xs - n

此函数向右旋转 n 位。

于 2016-04-25T17:11:32.753 回答