映射函数Haskell中的基础知识

时间:2015-12-10 16:01:48

标签: haskell

我自学Haskell并遇到了map功能的问题,并正在寻求帮助。我尝试做的是获取列表列表,如果列表为空,那么[]和其他列表中的一个列表中有一个1。然后取出1并将其放入[]列表。

a = [[2,1,3,1],[],[2,3],[1,2,3],[4]]

并制作

a = [[2,1,3,1],[1],[2,3],[2,3],[4]]
到目前为止,我有一些东西,我没有完整的东西。

((map (\k-> if ([])&&(elem 1 heads))a) 
where heads = map head a

但我也必须这样做才能a = [[1,2,1,3,1],[],[2,3],[1,2,3],[4]] 将给a = [[2,1,3,1],[1],[2,3],[1,2,3],[4]],因此它只会将一个1移到空列表中。

我知道这不行,但我现在已经尝试了几个小时,但我没有到达任何地方

4 个答案:

答案 0 :(得分:3)

在这里,我试图为a编写易于理解的功能解决方案 初学者。当然,这可以更有效地实施。

doStuff :: Integral a => [[a]] -> [[a]]
doStuff xs = let n = min holes donors in go n n xs
  where go _ _ []          = []
        go 0 m ([]:ys)     = []     : go 0       m ys
        go n m ([]:ys)     = [1]    : go (n - 1) m ys
        go n 0 ((1:zs):ys) = (1:zs) : go n       0 ys
        go n m ((1:zs):ys) = zs     : go n (m - 1) ys
        go n m (y:ys)      = y      : go n m       ys
        holes              = count null    xs
        donors             = count goodish xs
        count f            = length . filter f
        goodish (1:_)      = True
        goodish _          = False

它甚至有效:

λ> doStuff [[2,1,3,1],[],[2,3],[1,2,3],[4]]
[[2,1,3,1],[1],[2,3],[2,3],[4]]
λ> doStuff [[1,2,1,3,1],[],[2,3],[1,2,3],[4]]
[[2,1,3,1],[1],[2,3],[1,2,3],[4]]
λ> doStuff [[1,2,1,3,1],[],[2,3],[1,2,3],[4],[],[]]
[[2,1,3,1],[1],[2,3],[2,3],[4],[1],[]]

答案 1 :(得分:1)

这看起来像是一个以增量方式解决的可怕挑剔问题。因此,我建议你考虑单片解决方案。首先计算空列表的总数以及以1开头的列表总数。有了这些结果,再次攻击原始输入。如果您熟悉,foldl'可以轻松完成计数,或者您可以使用显式递归,或者如果您不关心效率,则可以过滤和计数两次;使用显式递归最终攻击最简单。

答案 2 :(得分:1)

如果从正确的方向接近,问题就很简单了。作为第一个近似值,您可以将函数定义为输入列表上的左侧折叠:

fun :: Eq a => a -> [[a]] -> [[a]]
fun z xss = newList 
  where (foundZ, newList, _) = foldl ... (False, [], False) xss

请注意,fold将返回两个值,即结果列表和一个布尔值,表示列表中是否找到1(或者在本例中为参数z)。第三个参数表示列表是否已被替换(我们只想进行一次替换)。如果我们聪明(我们将会),我们可以在传递给foundZ的函数体内使用foldl的值 - 也就是说,我们可以在它显然被计算之前使用它。剩下的就是将参数函数写入foldl:

\(fn,xss',rpl) xs ->
  case xs of 
    ...

考虑xs的不同可能性:它是空列表,它是包含z作为其头部的列表,以及每个其他列表:

    [] | not rpl -> ...
    (x:r) | x == z && not fn -> ...
    _  -> (fn, xs:xss',rpl)

请注意,当我们检查x == z时,我们也会检查not fn,因为我们只想从单个列表中选择一个z,所以如果我们已找到一个,我们就不会想再做一次。对于空列表,我们出于同样的原因检查not rpl。最后一种情况很明显,但前两种可能不是。

    [] | not rpl -> (fn, (if foundZ then [z] else []):xss', True)

空列表的情况简单检查是否找到z - 如果是,则返回包含z的单个列表。

    (x:r) | x == z && not fn -> (True , r:xss', rpl) 

z开头的列表的大小写为True返回found,并将该列表的 tail 添加到结果中(这是如何1被删除)。

把它们放在一起,你得到一个简单的功能:

fun :: Eq a => a -> [[a]] -> [[a]]
fun z xss = reverse newList 
  where (foundZ, newList, _) = 
          foldl 
            (\(fn,xss',rpl) xs ->
              case xs of 
                [] | not rpl -> (fn, (if foundZ then [z] else []):xss', True)
                (x:r) | x == z && not fn -> (True , r:xss', rpl) 
                _  -> (fn, xs:xss', rpl)
            ) (False, [], False) xss 

>fun 1 [[2,1,3,1],[],[2,3],[1,2,3],[4]]
[[2,1,3,1],[1],[2,3],[2,3],[4]]
>fun 1 [[1,2,1,3,1],[],[2,3],[1,2,3],[4]]
[[2,1,3,1],[1],[2,3],[1,2,3],[4]]

答案 3 :(得分:0)

IMO map对于这项工作来说并不是真正的功能。从概念上讲,map使用仅查看元素本身的函数来转换集合的每个元素。显然你可以编写一个map函数使用lambdas,范围等函数使用“外部”变量,但我建议尽可能接近map的概念。

“把那个1放在[]列表中的想法。”暗示(采取和放置)带有副作用的命令式方法,我们希望尽可能避免使用像haskell这样的纯函数式语言。

你可以用另一种方式来考虑它:没有必要实际“移动”1,即知道哪个1最终在哪个[]。计算空列表的数量(让我们称之为x)以及以1y)开头的列表数量就足够了,我们只需创建一个新列表< / p>

  • 使用min(x,y)
  • 替换空列表的第一个[1]次出现
  • 采用以tail
  • 开头的第一个min(x,y)列表中的1

可能的改进实施:

redistributeOnes :: [[Int]] -> [[Int]]
redistributeOnes xs = redistributeOnes' n n xs where
  n = min (length $ filter (==[]) xs) (length $ filter (\l -> if l == [] then False else (head l) == 1) xs)
  redistributeOnes' _ _ [] = []
  redistributeOnes' 0 0 xs = xs
  redistributeOnes' n m ([]:xs) | n > 0 = [1] : redistributeOnes' (n-1) m xs
                                | otherwise = [] : redistributeOnes' n m xs
  redistributeOnes' n m (x:xs)  | head x == 1 && m > 0 = (tail x) : redistributeOnes' n (m-1) xs
                                | otherwise = x : redistributeOnes' n m xs

试验:

λ> redistributeOnes [[], [1,2]]
[[1],[2]]
λ> redistributeOnes [[], [1,2], [], [], [1,2,3]]
[[1],[2],[1],[],[2,3]]
λ> redistributeOnes [[], [1,2], [], [1,2,3]]
[[1],[2],[1],[2,3]]
λ> redistributeOnes [[]]
[[]]
λ> redistributeOnes [[], [1,2,3]]
[[1],[2,3]]
λ> redistributeOnes [[1,2,3]]
[[1,2,3]]
λ> redistributeOnes [[1,2,3], [], [], [], [2,5,1], [1,2], [], [1,100]]
[[2,3],[1],[1],[1],[2,5,1],[2],[],[100]]