Haskell - 如果否则返回干净的元组

时间:2012-11-04 09:49:16

标签: list haskell tuples

我的作业任务是如果第一个元组的第二个元素与第二个元组的第一个元素相同,则将两个元组分组。然后,如果第一个元组是(a, b)而第二个元组是(b, c),则必须将元组(a, c)添加到结果列表中。

我写了第一个函数,它带有一个元组的元素和带有许多元组的第二个列表,并将每个元素进行比较。

这个适当地起作用:

c1 = ("a","x")
d1 = [ ("x","b"), ("z","c"), ("x","b"), ("z","c")
     , ("x","b"), ("z","c"), ("x","b"), ("z","c") ]

getByOne c1 a1 = filter (/=[])
  [ if (fst  (last(take n a1))) == (snd c1)
    then [((fst c1),  (snd  (last(take n a1))))]
    else  [] | n <- [1..(length a1) ] ]

输出:

[ [("a","b")], [("a","b")], [("a","b")], [("a","b")] ]

但问题是我不能投入,如果那么和else语句只是简单的元组,所以我创建了一个新的列表。在这个“解决方法”的最后,我将获得列表中的列表,依此类推。此外,如果输出列表更大,列表中会有更多列表。

有没有办法只传递元组或空元组,或者我应该以某种方式分组这些列表?

2 个答案:

答案 0 :(得分:9)

您可以使用

展平结果
concat :: [[a]] -> [a]

那么你甚至不需要filter (/=[]) - 顺便说一句,条件(/= [])更具惯用性not . null,因为null测试没有强制执行对其论点有一个Eq约束(你已经在这里有一个约束,所以这只是成语问题)。

此外,如果last (take n a1)n只是a1的第1 <= n <= length a1个元素。由于您施加了限制,因此可以更简洁地表达为a1 !! (n-1)

然后你有结构

getByOne c1 a1 = concat $ [something c1 (a1 !! i) | i <- [0 .. length a1 - 1]]

(我已经将索引转移到i的索引),这更清晰,更有效地表达为

getByOne c1 a1 = concat $ map (something c1) a1

如果您更喜欢列表理解为map,您也可以将其写为

getByOne c1 a1 = concat [something c1 x | x <- a1]

在你的情况下,使用alist-comprehension生成器中模式匹配的能力,给我们

getByOne (f,s) a1 = concat [ if a == s then [(f,b)] else [] | (a,b) <- a1]

更短,更易读。而不是使用if condition then [element] else []concat,更好的是在列表理解中使用条件,

getByOne (f,s) list = [(f,b) | (a,b) <- list, a == s]

简短明了。

答案 1 :(得分:3)

  1. [1..(length a1)]可以写成[1 .. length a1]
  2. [ if (fst  (last(take n a1))) == (snd c1)
      then [((fst c1),  (snd  (last(take n a1))))]
      else  [] | n <- [1..(length a1) ] ]
    

    可以写

    [ if fst lastElement == snd c1
      then [(fst c1, snd lastElement)]
      else [] | n <- [1 .. length a1 ]
              , let lastElement = last (take n a1) ]
    
  3. 然后,不要使用列表索引来完成它,而是直接使用列表:

    [ if x == snd c1
      then [(fst c1, y)]
      else [] | (x, y) <- a1 ]
    
  4. 然后,使用Maybe代替使用列表来表示解决方案的存在与否:

    import Data.Maybe
    
    c1 = ("a","x")
    d1 = [ ("x","b"), ("z","c"), ("x","b"), ("z","c")
         , ("x","b"), ("z","c"), ("x","b"), ("z","c") ]
    
    getByOne c1 a1 = catMaybes
            [ if x == snd c1
              then Just (fst c1, y)
              else Nothing | (x, y) <- a1 ]
    
  5. 更好的是,使用一名警卫并摆脱if then else:

    getByOne (a, b) a1 = [ (a, d) | (c, d) <- a1
                                  , b == c ]
    
  6. 或者,如果要使用过滤器,首先过滤匹配元组的列表,然后使用map构建相应的结果:

    getByOne (a, b) a1 = map (\(_, c) -> (a, c))
                         . filter (\(c, _) -> b == c)
                         $ a1
    

    简化为

    getByOne (a, b) = map (\(_, c) -> (a, c))
                         . filter (\(c, _) -> b == c)