Haskell 生成元素右移n次的列表

Haskell 生成元素右移n次的列表,haskell,Haskell,我最近在尝试一个问题。在这种情况下,我没有什么问题 Input: generatingListforRightShifting 2 [1,2,3,4,5,6,7,8] Output: [[1,2,3,4,5,6,7,8],[8,1,2,3,4,5,6,7],[7,8,1,2,3,4,5,6]] 正如您所理解的,这个程序将使一个元素向正确的方向移动。第一个参数表示它将执行多少次移位。 作为一个新手,我正在尝试解决几个著名的列表函数。以及使用递归。但对我来说,递归的概念并不清楚。我的代码是: ge

我最近在尝试一个问题。在这种情况下,我没有什么问题

Input: generatingListforRightShifting 2 [1,2,3,4,5,6,7,8]
Output: [[1,2,3,4,5,6,7,8],[8,1,2,3,4,5,6,7],[7,8,1,2,3,4,5,6]]
正如您所理解的,这个程序将使一个元素向正确的方向移动。第一个参数表示它将执行多少次移位。 作为一个新手,我正在尝试解决几个著名的列表函数。以及使用递归。但对我来说,递归的概念并不清楚。我的代码是:

generatingListforRightShifting' _ []=[]
generatingListforRightShifting' 0 x=x
generatingListforRightShifting' n xs=   newList where
                        newList=takeWhile(\i->[1..n] 
                                            <=n)(reverse(take 
                                           i(reverse xs))++reverse(drop i(reverse xs)))
generatingListforRightShifting'.[]=[]
为右移“0 x=x”生成列表
GeneratingListForRightShift'n xs=newList其中
newList=takeWhile(\i->[1..n]
您可以递归地定义“shift:
shift 0
是一个no op,
shift 1+n(x:xs)
shift n xs

比如:

shift 0 = \x -> x
shift n = \lst@(x:xs) -> (shift (n-1) xs)

-- example:
sh3 = shift 3        
然后,“旋转”问题变得更容易:

rotate n = \lst -> (shift lst) ++ (take n lst)

这通常被称为旋转而不是移位。将列表向右旋转一次很简单,因为有很多方法可以获得和

还请注意,旋转两次相当于调用旋转两次。因此,该方法可以简单地实现为前一个结果的递归:

rotateN 0 lst = [lst]
rotateN n lst = lst : rotateN (n-1) ((last lst):(init lst))

(注意:这可能不是最佳解决方案。)

我将放弃当前非常复杂的方法。相反,请专注于抽象操作的不同组件。如果将操作分解为多个部分,您将注意到有两个对称组件:向左旋转列表和向右旋转列表。您希望定义的操作会迭代右旋转在某些列表上的指定次数。这表明可以通过左旋转或右旋转的指定次数的迭代来定义所需的操作。例如

left :: [a] -> [a]
left [] = []
left xs = tail xs ++ [head xs]

right :: [a] -> [a]
right [] = []
right xs = last xs : init xs

shiftL :: Int -> [a] -> [[a]]
shiftL n = take n . iterate left

shiftR :: Int -> [a] -> [[a]]
shiftR n = take n . iterate right

在这里使用
循环
似乎不错:

shifts n xs = take (n+1) $ shifts' (cycle xs)
  where
    len = length xs
    shifts' ys = take len ys:shifts' (drop (len-1) ys)

你似乎更喜欢我们修复你的代码而不是重新开始,所以 让我们看一下您的代码。首先,主要列表切分:

reverse (take i (reverse xs)) ++ reverse (drop i (reverse xs)) 
现在
reverse(取i(反向xs))
从列表末尾取
i
元素, 但是,为了实现这一点,您需要将列表反转两次,这样做会更好
drop(length xs-i)xs
。同样,您可以实现
reverse(drop i(reverse xs)))
as
取(长度xs-i)xs
。这给了我们

drop (length xs - i) xs ++ take (length xs - i) xs 

现在,您的代码
\i->[1..n]我发现使用
splitAt
左旋转非常笔直:

import Data.Tuple (swap)
rotateLeft n = uncurry (++) . swap . splitAt n

> rotateLeft 2 "Hello World!"
>>> "llo World!He"

那将是
drop
,而不是“shift”,意思是“轮换”。@DanielFischer:是的,我意识到我读了一半这个问题太晚了。“旋转”是个好名字。thnx到uxtolf。实际上,作为一名初学者,我尝试使用简单的操作,如头部、尾部、重复。出于这个原因,我尝试这个问题。我不想彻底修改代码。takewhile之后的FLOWING端口(反转(take i(reverse xs))++反转(drop i(reverse xs)))适用于单时间移位。我想将其用于多时间移位。你能帮我吗?顺便说一句,thx和非常非常thnx fr ureffrt@is7s:我想强调,例如,
rotate 2
是一个从列表创建新列表的函数;也许不需要。
如果你问我的话,服用(n+1)$iterate rotateOnce lst
。thnx Kenny。但是我不想完全改变我的剂量。我想编辑takewhile的部分。该“(反转(取ni(反转xs))++反转(下降n(反转xs)))”用于移动元素。现在我想多次使用这个部分,而不需要递归调用。太多了……但你能告诉我吗?在第三行,我想你需要的是[head xs],而不是head xs.@SaugataBose抱歉,修好了。
[drop (length xs - i) xs ++ take (length xs - i) xs | i <- [1 .. length xs], i <= n]
[drop (length xs - i) xs ++ take (length xs - i) xs | i <- [1..n]]
[drop j xs ++ take j xs | j <- [length xs,length xs - 1 .. length xs - n]]
let l = length xs in
  [drop j xs ++ take j xs | j <- [l,l - 1 .. l - n]]
let l = length xs in
  take n [drop j xs ++ take j xs | j <- [l,l - 1 .. 0]]
rotationsR n xs = let l = length xs in
  take n [drop j xs ++ take j xs | j <- [l,l - 1 ..]]
rotationsL n xs = take n [drop j xs ++ take j xs | j <- [0..length xs]]
 [[1,2,3,4],[2,3,4,1],[3,4,1,2],[4,1,2,3],[1,2,3,4],[2,3,4,1],[3,4,1,2],[4,1,2,3],[1,2,3,4],[2,3,4,1]]
rotationsR' n xs = let l = length xs in
  take n . map (reverse.take l) . tails . cycle . reverse $ xs
generatingListforRightShifting n xs = 
    [reverse (take i (reverse xs)) ++ reverse (drop i (reverse xs)) | i <- [1..n]]
import Data.Tuple (swap)
rotateLeft n = uncurry (++) . swap . splitAt n

> rotateLeft 2 "Hello World!"
>>> "llo World!He"