如何以表格形式显示列表中的数据

时间:2018-02-24 10:59:21

标签: haskell

- [(教师,主题,类,extrasub)]

test =[("Sam","Maths","Std5","PE"),
       ("Sam","Maths","Std7","PE"),
       ("Sam","geography","Std6","PE"),
       ("Jake","English","Std9","Red Cross"),
       ("Jake","English","Std9","Guards")]

看起来应该是这样的

    Teacher         Subject     Class   ExtraClass
    Sam             Maths       Std5    PE
                                Std7
                    Geography   Std6
    Jake            English     Std9    Red Cross
                                        Guards

我希望输出像这样

[
("Jake","English","Std9","Red Cross"),
("","","","Guards"),
("Sam","Maths","Std7","PE"),
("","","Std5",""),
("","geography","Std6","PE")]



test2 :: [([Char], [Char], [Char], [Char])]
test2 = test3 $ concat $ groupBy (\(x,_,_,_) (y,_,_,_) -> x==y) (sort test1)

test3 [] = []
test3 [x] = []

test3 ((a1,b1,c1,d1):(a2,b2,c2,d2):xs) =
                                        if(a1==a2 && b1== b2&& d1==d2)
                                            then [("","",c1,d1)]
                                         else if (a1==a2)
                                            then [("","",c1,d1)]
                                         else [("",b1,c1,d1)]

我正在考虑使用foldl的这种方法,但无法得到它。关于如何进行此任何建议

1 个答案:

答案 0 :(得分:3)

实际上这很难。你必须解决两个问题:

  1. 如何转换输入,以便将连续行中的重复字段替换为空白 空间。

  2. 如何在漂亮的列中打印结果。

  3. 让我们逐一讨论这些问题。

    1. 转换输入。

      我们该怎么办?如果任何给定的连续单元格中存在重复值 列,我们想用空格替换所有这些,除了第一个。所以,我们可能会这样做 像这样:

      1. 将每列分析为列表。

      2. 如果存在重复值,请仅保留第一个值,并将所有其他值替换为空白 空间。

      3. 棘手的时刻是,如果第一列的值发生变化,我们想停止 消隐单元并至少打印一行。为了确保这一点,我们可能会打破这个局面 部分,以便对于第一列的每个可能值,有一个部分。

      4. 我们如何做到这一点?我的看法:

        -- First, I'd like to define some type synonyms to make type signatures more
        -- intuitive.
        
        type Row = [String]
        
        type Table = [Row]
        
        -- It would be easier to deal with a row represented as a list, rather than a
        -- tuple.
        
        tupleToList :: (String, String, String, String) -> Row
        tupleToList (a, b, c, d) = [a, b, c, d]
        
        -- With some handy library functions, we can convert our input to Rows and
        -- section it by teacher's name in one pass:
        
        test' :: [Table]
        test' = groupBy equalFirstColumn . map tupleToList $ test
          where
            equalFirstColumn = ((==) `on` head)
        
        -- Now, we have to blank the repeating values. If the columns were lists, we
        -- would do it like this:
        
        blankRepetitions :: [String] -> [String]
        blankRepetitions (x:xs) = x: replicate (length bef) "" ++ blankRepetitions aft
            where (bef, aft) = span (== x) xs
        blankRepetitions [ ] = [ ]
        
        -- Luckily, there is a library function that can turn columns to rows and vice
        -- versa. Let's use it.
        
        test'' :: [Table]
        test'' = map (transpose . map blankRepetitions . transpose) test'
        
        -- Now we can turn our groups back into a single table. Why not add a row with
        -- column captions as well.
        
        test3 :: Table
        test3 = ["Teacher", "Subject", "Class", "ExtraClass"] : concat test''
        

        花点时间研究一下,看看它是否按预期工作。我怀疑地挥之不去 我处理消隐的方式有一些缺陷......

      5. 打印结果。

        到目前为止,获取漂亮表格的最简单方法就是用空格填充每个单元格 这样每个单元格的宽度都相同:

        pad :: Int -> String -> String
        pad w s = " " ++ s ++ (replicate (w - length s) ' ')
        

        但选择什么宽度?最长的细胞的宽度似乎是一个不错的选择。所以,我们可以去 那样:

        columnize :: Table -> String
        columnize xss = unlines . map concat . (map.map) (pad maxwidth) $ xss
            where maxwidth = maximum . map length . concat $ xss
        

        请注意map.map如何处理列表列表的方式与单个map处理的方式相同 一个简单的。

      6. 就是这样!看一下如何将一个复杂的问题转化为一个很容易的问题 较小的。