【问题标题】:Transform a list into a list of lists with fold in haskell在haskell中将列表转换为带有折叠的列表列表
【发布时间】:2021-02-17 14:53:41
【问题描述】:

我有这个代码:

fromList :: Int -> [Int] -> [[Int]]
fromList y = takeWhile (not.null) . map (take y) . iterate (drop y) 

这样做的一个例子: -> fromList 4 [1..19]

[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16],[17,18,19]]

如何使用折叠来制作这段代码?

【问题讨论】:

  • 提示:使用[[a]] 作为累加器的类型。
  • 为什么?好点了吗?
  • 这真的是unfoldr的工作;为什么要使用foldr
  • 虽然(我认为)任何一方都可以完成另一方的工作,但折叠适用于具有一般形式 [a] -> a 的事物,而展开则适用于 a -> [a]。 (a本身可以是列表类型,考虑到两个函数的重叠。)
  • 考虑fromList n = unfoldr (\x -> if null x then Nothing else Just (take n x, drop n x))

标签: list haskell fold chunks sublist


【解决方案1】:

这是一个使用foldr 的非常优雅的解决方案:

fromList :: Int -> [a] -> [[a]]
fromList n = foldr (\v a ->
    case a of
        (x:xs) -> if length x < n then (v:x):xs else [v]:a
        _ -> [[v]]
    ) []

本质上,累加器是结束值,对于列表中的每个值,它会检查是否还有空间将其放入现有块中,如果没有,则将其放入新块中。遗憾的是,由于使用了foldr,额外的元素被放在左侧而不是右侧。这可以通过使用foldl(或foldl')稍慢(可能更丑陋)的方法来解决:

fromList :: Int -> [a] -> [[a]]
fromList _ [] = []
fromList n (x:xs) = reverse $ foldl (\a@(y:ys) v ->
    if length y < n
        then (y ++ [v]):ys
        else [v]:a
    ) [[x]] xs

【讨论】:

  • 我给出了 2 个可能的解决方案,第一个将额外的块放在左侧,导致 [[1], [2, 3, 4], [5, 6, 7], [8, 9, 10]],第二个导致 [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]],正如我在回答中所说。跨度>
  • a@ 表示a 成为y:ys 的别名。您可以使用y:ys 而不是a,如果需要,可以去掉a@
【解决方案2】:

这是一种方法。

foo :: Int -> [t] -> [[t]]
foo k xs | k > 0  =  foldr cons [] .
          zip xs . cycle $ (False <$ [2..k]) ++ [True]
  where
  cons (a,True)   ys  =  [a] : ys
  cons (a,False)  ys  =  (a:x) : zs
                         where
                         (x,zs) | null ys   = ([], [])
                                | otherwise = (head ys, tail ys)

-- > foo 3 [1..10]
-- => [[1,2,3],[4,5,6],[7,8,9],[10]]

-- > take 4 . foo 3 $ [1..]
-- => [[1,2,3],[4,5,6],[7,8,9],[10,11,12]]

-- > take 3 . map (take 2) . foo 3 $ [1..8] ++ undefined
-- => [[1,2],[4,5],[7,8]]

它会按照您的描述创建输出,并且以足够懒惰的方式执行此操作,因此它也适用于无限列表。

edit: 让它变得更加懒惰,以便最后一个示例可以工作,基于the idea by Daniel Fischer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-25
    • 2011-03-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多