Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List Haskell中的所有列表旋转_List_Haskell_Functional Programming - Fatal编程技术网

List Haskell中的所有列表旋转

List Haskell中的所有列表旋转,list,haskell,functional-programming,List,Haskell,Functional Programming,我有一个旋转列表的功能: rotate :: [a] -> [a] rotate [] = [] rotate (x:xs) = xs ++ [x] 现在我想要一个函数,它给出一个列表,其中包含有限列表的每一个可能的旋转: rotateAll :: [a] -> [[a]] 在命令式语言中,我会做一些类似(伪代码)的事情 当然,强制思考可能无助于我找到解决这个问题的功能性解决方案。我正在寻找一些关于如何解决这个问题的提示 其他想法: 为了解决这个问题,我有两个问题要解决。首先,我

我有一个旋转列表的功能:

rotate :: [a] -> [a]
rotate [] = []
rotate (x:xs) = xs ++ [x]
现在我想要一个函数,它给出一个列表,其中包含有限列表的每一个可能的旋转:

rotateAll :: [a] -> [[a]]
在命令式语言中,我会做一些类似(伪代码)的事情

当然,强制思考可能无助于我找到解决这个问题的功能性解决方案。我正在寻找一些关于如何解决这个问题的提示

其他想法:

为了解决这个问题,我有两个问题要解决。首先,我需要反复旋转一个列表,并将每个结果收集到一个列表中。因此,第一个解决方案需要执行以下操作

rotateAll xs = [xs (rotate xs) (rotate (rotate xs)) (rotate (rotate (rotate xs))) ...]
当然我不知道要做多少次。我可以无限地这样做,然后使用
take(length xs)
来获得我想要的有限数量的列表。这实际上说明了第二个问题:确定何时停止。我不知道使用
take
是否是解决此问题的最有效或最优雅的方法,但我在键入此内容时想到了这一点,并且应该可以工作

附录:
现在,我已经找到了两个解决方案,一个是我自己的,另一个是有提示的。我将很高兴地欢迎任何其他更快或使用不同方法的解决方案。谢谢

除此之外,您还可以编写一个函数来生成n个旋转的列表。案例n=0将把输入包装在一个列表中,案例n=m+1将把输入附加到案例m的结果中。虽然通常首选使用标准函数,但有时编写自己的解决方案是有益的。

我提出了两种解决方案。第一个是在我发布问题后出现的手工制作的:

rotateAll :: [a] -> [[a]]
rotateAll xs = rotateAll' xs (length xs)
    where rotateAll' xs 1 = [xs]
          rotateAll' xs n = xs : rotateAll' (rotate xs) (n - 1)
另一个使用@Tilo的建议:

rotateAll :: [a] -> [[a]]
rotateAll xs = take (length xs) (iterate rotate xs)

你可能也想考虑这个网站回答同样的问题。


由于注释而编辑:基于
旋转的实现以及基于
初始化的实现和
尾部的实现应该是列表长度的二次方。但是,基于
inits
tails
的方法效率应该较低,因为它执行多个二次遍历。但是请注意,只有在完全评估结果时,这些语句才有效。此外,编译器可能能够改进代码,因此您必须谨慎对待这些语句。

您也可以递归生成它们。生成空列表或单个元素列表的所有旋转非常简单,而生成
x:xs:xs的旋转则是将
x
插入
xs
所有旋转的正确位置

您可以通过生成要插入的索引(假设前面的旋转是按此顺序进行的,只需列表[1,2,…])并使用
zipWith
x
插入到正确的位置来完成此操作


或者,您可以使用
inits
tails
组合来
拆分
围绕位置的旋转,并使用
zipWith
将它们粘在一起。

使用
数据中的预定义函数。List
!您可以使用四个函数调用、无递归和无
rotate
函数获得所有旋转的列表

您要求不要在此处发布完整的解决方案。对于那些想看到它的人,一个完整的解决方案(一行代码)出现在

附录:现在,我已经找到了两个解决方案,或者是我自己的,或者是有提示的。 我将很高兴地欢迎任何其他更快或更实用的解决方案 不同的方法。谢谢

由于没有其他人指出使用
cycle
我想我会为有限列表添加此解决方案:

rotations x = let n = length x in map (take n) $ take n (tails (cycle x))
对于无限列表
x
,旋转只是
尾部x

计算
循环x
是O(n)时间和空间,
尾部的每个元素是O(1),
take n
是O(n)时间和空间,但这两个
take n
是嵌套的,因此计算整个结果是O(n^2)时间和空间

如果它在惰性地生成下一个旋转之前垃圾收集每个旋转,那么空间理论上是O(n)


如果你对自己的消费量很了解,那么你就不需要
map(take n)
,只需走
循环x
take n(tails(cycle x))
并保留空间O(n)。

这是一个在旋转列表本身和列表中的每个条目上都完全懒惰的版本。关键在于,与其预先计算长度,不如在运行时将结果中的元素与列表中的元素进行匹配,在输入列表用完时停止

rotations xs = map (takeSame xs) $ takeSame xs (tails (xs ++ xs)) where
    takeSame [] _ = [] 
    takeSame (_:xs) (y:ys) = y:takeSame xs ys
此外,由于它使用了尾部,并且仅使用单一浓缩,因此它在记忆方面的表现比其他一些选择要好得多。当然,它也可以正确地处理无限列表

rotations (x:xs) = (xs++[x]):(rotations (xs++[x]) ) 
这将创建连续的惰性旋转 现在只需要第一个唯一的,它将等于原始列表的长度

take (length xs) (rotations xs)
从头开始:

data[]a=[]a:[a]
结束::a->[a]->[a]
结束y[]=y:[]
结束y(x:xs)=x:y`end`xs
--这样`end x xs=xs++[x]`
旋转::[a]->[[a]]
旋转[]=[]
旋转X=旋转X
哪里
rots xs@(x:xs')=xs:rots(x`end`xs'))
--无限旋转列表
旋转::[a]->[[a]]
旋转X=旋转X(旋转X)
哪里
rots[].[]
rots(uuxs)(r:rs)=r:rots xs-rs
--所有唯一旋转,`forall xs.`相当于`take
--(长度xs)(旋转xs)`
或:

{-#语言模式}
旋转::[a]->[a]
旋转[]=[]
旋转(x:xs)=x`end`xs
哪里
结束y[]=y:[]
结束y(x:xs)=x:end y xs
迭代::Int->(a->a)->a->[a]
迭代0=[]
迭代n f x=的情况f x
x'->x':迭代(n-1)fx'
长度::[a]->Int
长度xs=长度0 xs
哪里
伦恩!n[]=n
伦恩!n(n:xs)=len(n+1)xs
旋转::[a]->[[a]]
旋转X
take (length xs) (rotations xs)
rotations :: [a] -> [[a]]
rotations xs = take (length xs) (iterate (\(y:ys) -> ys ++ [y]) xs)
import Data.List
rotate x=[take (length x) $ drop i $ cycle x | i<-[0..length x-1]]