Zoznamy — úloha

Ciele

  1. Vyskúšať vyriešenie väčšej úlohy.

Postup

Krok 1: Komplexnejšia úloha

Úloha 1.1

Definujte funkciu, ktorá vykreslí histogram zo zadaného zoznamu prostredníctvom znakov |. Pričom nech je vykreslená aj legenda — čísla položiek dole a hodnoty naľavo. Pritom nech je v legende vypísaná len každá piata hodnota. Napr. pre zoznam [1,5,3,2,4,1,5,8,7,9,10,6,6,7,5,4,2,2,1] nech je výsledok:

*Main> putStr (histogram values)
10                     |
                     | |
                 |   | |
                 | | | |     |
                 | | | | | | |
 5   |         | | | | | | | | |
     |     |   | | | | | | | | | |
     | |   |   | | | | | | | | | |
     | | | |   | | | | | | | | | | | |
   | | | | | | | | | | | | | | | | | | |
   0         5        10        15
values :: [Int]
values = [1,5,3,2,4,1,5,8,7,9,10,6,6,7,5,4,2,2,1]

histogram :: [Int] -> String
histogram = undefined

Riešenie

main :: IO ()
main = putStr (histogram values)

values :: [Int]
values = [1,5,3,2,4,1,5,8,7,9,10,6,6,7,5,4,2,2,1]

histogram :: [Int] -> String
histogram values = unlines ((legendC `above` ["  "]) `beside` (body `above` legendL))
    where
        body = histogramBody values
        legendL = [legendLine width]  
        legendC = legendColumn height
        width = length values
        height = maximum values

above :: [String] -> [String] -> [String]
above = (++)

beside :: [String] -> [String] -> [String]
beside = zipWith (++)

histogramBody :: [Int] -> [String]
histogramBody values = map (histogramLine values) levels
    where levels = reverse [1..maximum values]

histogramLine :: [Int] -> Int -> String
histogramLine values level = concatMap cell values
    where cell x | x >= level = " |"
                 | otherwise  = "  "

legendLine :: Int -> String
legendLine width = concatMap (rfill 2 . legendLabel) [0..width-1]

legendColumn :: Int -> [String]
legendColumn height = map (rfill 2 . legendLabel) (reverse [1..height])

legendLabel :: Int -> String
legendLabel x | x `mod` 5 == 0 = show x
              | otherwise      = ""

rfill :: Int -> String -> String
rfill width str = replicate (width - length str) ' ' ++ str

Poznámka

Implementáciu rozdeľte na niekoľko samostatných funkcií, napríklad:

histogramBody :: [Int] -> [String]
legendLine :: Int -> String
legendColumn :: Int -> [String]