【问题标题】:Get all rotations for a string in haskell获取haskell中字符串的所有旋转
【发布时间】:2020-10-28 13:17:37
【问题描述】:

所以我正在尝试创建一个函数“rot”,它接受一个字符串并返回一个具有所有可能旋转的字符串列表,例如 rot “abc”返回 [“abc”,“bca”,cab”],似乎用其他语言做起来很简单,但我是haskell的新手,所以我想不出办法。这就是我到目前为止所拥有的:

rot :: [Char] -> [[Char]]
rot word = 
    let
        lst = [tail word ++ [head word]]
    in
        lst
    

main = do
    print(rot "abc")

它按预期返回“bca”,但我想要一种查找所有旋转并将其存储在列表中的方法。

这是python中的一个例子

def rot(word):
    lst = []
    for i in range(len(word)):
        newWord1 = word[0:i]
        newWord2 = word[i:]
        newWordResult = newWord2 + newWord1
        lst.append(newWordResult)
    return lst

【问题讨论】:

  • 你能举个例子说明你在其他语言中是如何做到的吗?
  • 我在问题中添加了一个python示例

标签: haskell


【解决方案1】:

嗯,您可以或多或少地直接翻译您的 Python 代码。在函数式编程中习惯使用递归而不是迭代,从length word 倒数到零更方便。除此之外,几乎是一样的:

rot word =
  let loop 0 lst = lst
      loop i lst =
        let newWord1 = take (i-1) word
            newWord2 = drop (i-1) word
            newWordResult = newWord2 ++ newWord1
        in loop (i-1) (newWordResult : lst)

  in loop (length word) []

【讨论】:

  • 伙伴,非常感谢!这个解释不仅回答了我的问题,而且让我更好地理解了“让”的表达方式!我真的很感激!
  • 很高兴我能帮上忙
  • "例如 rot "abc" 返回 ["abc", "bca", cab"]" 不成立。或者,也许 OP 不关心实际订单......
  • @WillNess 啊,软件三大难题之一! :-)
  • 已修复。起初我想把它作为练习留给读者,但后来我的强迫症胜出了。
【解决方案2】:

可以使用列表的tailsinits

Prelude Data.List> tails "abc"
["abc","bc","c",""]
Prelude Data.List> inits "abc"
["","a","ab","abc"]

因此我们可以将其用于:

import Data.List(inits, tails)

rotated :: [a] -> [[a]]
rotated xs = [x ++ y | (x@(_:_), y) <- zip (tails xs) (inits xs)]

这会产生:

Prelude Data.List> rotated "abc"
["abc","bca","cab"]
Prelude Data.List> rotated [1,4,2,5]
[[1,4,2,5],[4,2,5,1],[2,5,1,4],[5,1,4,2]]
Prelude Data.List> rotated [1.0,3.0,0.0,2.0]
[[1.0,3.0,0.0,2.0],[3.0,0.0,2.0,1.0],[0.0,2.0,1.0,3.0],[2.0,1.0,3.0,0.0]]

或者作为@Iceland_jack says,我们可以使用ParallelListComp扩展来允许在列表理解中并行迭代两个列表,而无需显式使用zip

{-# LANGUAGE ParallelListComp #-}

import Data.List(inits, tails)

rotated :: [a] -> [[a]]
rotated xs = [x ++ y | x@(_:_) <- tails xs | y <- inits xs]

【讨论】:

  • -XParallelLispComp 让你写[ x ++ y | x@(_:_) &lt;- tails xs | y &lt;- inits xs ]
  • 您也可以使用init 代替那种奇怪的模式匹配,但由于init (还没有?)与列表融合进行交互,您的方式可能更快。
【解决方案3】:

这很简单

rotations xs = map (take n) . take n
                 . tails $ xs ++ xs
   where
   n = length xs

如果可能的话,习惯上避免使用length,尽管这里会导致代码更加复杂(*) (但通常它会导致更简单、更清晰的代码更符合问题的真实性质),

rotations2 xs = map (zipWith (\a b -> b) xs) 
                 . zipWith (\a b -> b) xs
                 . tails $ xs ++ xs

测试,我们得到

> rotations "abcd"
["abcd","bcda","cdab","dabc"]

> rotations2 "abcd"
["abcd","bcda","cdab","dabc"]

> take 4 . map (take 4) $ rotations2 [1..]
[[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7]]

(*)edit其实,它应该有它自己的名字,

takeLength :: [a] -> [b] -> [b]
takeLength  =  zipWith (\a b -> b)

rotations2 xs = map (takeLength xs) 
                 . takeLength xs
                 . tails $ xs ++ xs

【讨论】:

    猜你喜欢
    • 2013-04-24
    • 1970-01-01
    • 1970-01-01
    • 2012-09-14
    • 1970-01-01
    • 2016-05-23
    • 2014-02-13
    • 2021-03-30
    • 1970-01-01
    相关资源
    最近更新 更多