这可能是一个愚蠢的问题,但我对 Haskell 很陌生。(实际上我几个小时前才开始使用它。)
所以我的问题是我有一个包含 4 个元素的列表,我需要在一行上打印两个,在新行上打印两个。
这是列表:
let list1 = ["#", "@", "#", "#"]
我需要输出如下所示:
#@
##
我知道我可以使用以下内容在新行上打印每个元素:
mapM_ putStrLn list1
但我不确定如何调整它以仅在新行上打印列表的一部分。
你想要像Data.Text.chunksOf
任意列表这样的东西,我在任何地方都没有见过,所以我总是重新实现它。
import Data.List (unfoldr)
-- This version ensures that the output consists of lists
-- of equal length. To do so, it trims the input.
chunksOf :: Int -> [a] -> [[a]]
chunksOf n = unfoldr (test . splitAt n) where
test (_, []) = Nothing
test x = Just x
然后我们可以把你的[String]
变成[[String]]
,一个列表的列表,每个列表对应于String
一行的组件。我们map
concat
通过该列表合并其组件中的每一行,然后unlines
将它们全部粘合在一起。
grid :: Int -> [String] -> String
grid n = unlines . map concat . chunksOf n
然后我们可以根据需要打印该字符串
main :: IO ()
main = putStrLn $ grid 2 list1
编辑:显然有chunksOf
一个相当流行的库Data.List.Split。据我所知,他们的版本与我的相同,尽管它的实现方式略有不同。我们俩都应该满足
chunksOf n xs ++ chunksOf n ys == chunksOf n (xs ++ ys)
每当length xs `mod` n == 0
。
查看tel link Data.List.Split,可以使用 Chop 构建另一个解决方案。
定义如下进入库,
chop :: ([a] -> (b, [a])) -> [a] -> [b]
chop _ [] = []
chop f as = b : chop f as'
where (b, as') = f as
然后遵循 simeon 的建议,我们以这一个班轮结束,
let fun n = mapM_ putStrLn . chop (splitAt n)
Chop 似乎是一个不错的功能,足以在此处提及以说明替代解决方案。(展开也很棒)。
你可以做:
mapM_ putStrLn [(take 2 list1), (drop 2 list1)]
wheretake
并drop
返回具有预期元素数量的列表。take 2
接受两个元素并drop 2
删除前两个元素。
初学者尝试:
myOut :: [String] -> IO ()
myOut [] = putStr "\n"
myOut (x:xs) =
do if x=="@"
then putStrLn x
else putStr x
myOut xs
ghci>myOut ["#", "@", "#", "#"]
#@
##
ghci>