我最近在尝试一个问题。在这种情况下,我遇到的问题很少。
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)))
据我所知,我正在做的主要错误是在部分takeWhile。但我怎么能迭代n次。我已经制作了一个直接显示移位结果的程序,如 输入:generatingListforRightShifting 2 [1,2,3,4,5,6,7,8] 产出:[7,8,1,2,3,4,5,6] 但是,当我试图获得所有先前的转变时,我不能。
任何人都可以帮助我。如果你给我解决的想法,我也欢迎你。
答案 0 :(得分:3)
这通常被称为旋转而不是移位。右侧旋转列表很简单,因为有方法可以获取last element和sublist of all elements but the last。
rotateOnce lst = (last lst):(init lst)
另请注意,旋转两次相当于调用rotateOnce两次。因此,该方法可以简单地实现为来自先前结果的递归:
rotateN 0 lst = [lst]
rotateN n lst = lst : rotateN (n-1) ((last lst):(init lst))
(注意:这可能不是最佳解决方案。)
答案 1 :(得分:2)
您可以递归定义“shift”:shift 0
是无操作,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)
答案 2 :(得分:2)
您似乎更喜欢我们修复您的代码而不是重新开始,所以 让我们来看看你的代码。首先,主要列表斩:
reverse (take i (reverse xs)) ++ reverse (drop i (reverse xs))
现在reverse (take i (reverse xs))
从列表末尾获取i
个元素,
但是为了达到这个目的,你将列表反转两次,这样做会更好
drop (length xs - i) xs
。同样,您可以实施reverse (drop i (reverse xs)))
为take (length xs - i) xs
。这给了我们
drop (length xs - i) xs ++ take (length xs - i) xs
现在您的代码\i->[1..n]<=n
没有意义,因为它会比较列表[1..n]
与n
,这是行不通的。我想你正在努力建立一个i
运行的循环
1
到n
,这是一个很好的计划。让我们使用列表理解来获得我们想要的那些:
[drop (length xs - i) xs ++ take (length xs - i) xs | i <- [1 .. length xs], i <= n]
但是现在我们从1开始运行到列表的长度但丢弃了n
以上的数字,
哪个会写得更好
[drop (length xs - i) xs ++ take (length xs - i) xs | i <- [1..n]]
这允许n
超过length xs
,但我没有看到一个大问题,我们可以先检查一下。
现在请注意,我们仅使用i
形式的(length xs - i)
,我们真的在重新计算
length xs
比我们应该做的多得多,所以不要让i
从1
运行到n
,而是使用
length xs - i
,我们为什么不j=length xs -i
j
length xs
从length xs - n
到[drop j xs ++ take j xs | j <- [length xs,length xs - 1 .. length xs - n]]
:
[6,5..1] == [6,5,4,3,2,1]
因为例如let l = length xs in
[drop j xs ++ take j xs | j <- [l,l - 1 .. l - n]]
这样做比较简洁
take
或者你可能比let l = length xs in
take n [drop j xs ++ take j xs | j <- [l,l - 1 .. 0]]
更喜欢做算术,所以我们可以使用:
generatingListforRightShifting
它有额外的好处,可以阻止你做太多,停止 当你回到起点时。
我会将您的功能从rotationsR
重命名为rotationsR n xs = let l = length xs in
take n [drop j xs ++ take j xs | j <- [l,l - 1 ..]]
,并提供
rotationsR 6 [1..4] == [[1,2,3,4],[4,1,2,3],[3,4,1,2],[2,3,4,1],[1,2,3,4]]
提供rotationsL n xs = take n [drop j xs ++ take j xs | j <- [0..length xs]]
。
左旋转看起来更简单:
xs
题外话:我无法自拔,抱歉,我又开始了。
我仍然不喜欢所有那些每次都掉下来的东西,我宁愿自大
无限多个cycle xs
的副本彼此相邻(tails
)并无限采取
许多cycle xs
,将它们全部砍成正确的长度,但只是给你第一个n:
rotationsL'n xs = let l = length xs in 拿n。地图(拿l)。尾巴。循环$ xs
由于懒惰评估,只计算了有限数量的rotationsL' 10 [1..4]
,
但是这个可以运行并运行: [[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]]
Undigression:如果你想更贴近原始代码,你可以做到
{{1}}
答案 3 :(得分:1)
我会放弃当前的方法,这是非常复杂的。相反,专注于抽象操作的不同组件。如果将操作分解为多个部分,您会注意到有两个对称组件:向左旋转列表,向右旋转列表。您希望定义的操作在某个列表上迭代右旋转指定的次数。这表明可以通过 左或右旋转指定指定数量的迭代来定义所需操作>。例如,
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
答案 4 :(得分:1)
在这里使用cycle
似乎不错:
shifts n xs = take (n+1) $ shifts' (cycle xs)
where
len = length xs
shifts' ys = take len ys:shifts' (drop (len-1) ys)
答案 5 :(得分:1)
我发现左旋转使用splitAt
非常直接:
import Data.Tuple (swap)
rotateLeft n = uncurry (++) . swap . splitAt n
> rotateLeft 2 "Hello World!"
>>> "llo World!He"