Browse Source

Day 7 - Foldable instance for summing up directories

main
Jens Kadenbach 2 years ago
parent
commit
435a06fd59
4 changed files with 30 additions and 32 deletions
  1. 3
    6
      src/Day7.hs
  2. 25
    24
      src/Day7/Interpreter.hs
  3. 1
    1
      src/Day7/Parser.hs
  4. 1
    1
      test/Day7Spec.hs

+ 3
- 6
src/Day7.hs View File

13
    let parsed = forceRight $ parseTerminalLines input
13
    let parsed = forceRight $ parseTerminalLines input
14
    let tree = buildTree parsed
14
    let tree = buildTree parsed
15
    let small = filterDirectories (<= 100000) tree
15
    let small = filterDirectories (<= 100000) tree
16
-   let sumOfSmall = sumUp small
16
+   let sumOfSmall = sum small
17
    putStrLn ("Sum of those directories is " ++ show sumOfSmall)
17
    putStrLn ("Sum of those directories is " ++ show sumOfSmall)
18
-   let rootSize = snd . head $ sizeOfDirectories tree
19
-   putStrLn ("Root size is " ++ show rootSize)
18
+   let rootSize = head $ sizeOfDirectories tree
20
    let freeSpace = 70000000 - rootSize
19
    let freeSpace = 70000000 - rootSize
21
    let requiredSpace = 30000000 - freeSpace
20
    let requiredSpace = 30000000 - freeSpace
22
-   putStrLn ("Required space is " ++ show requiredSpace)
23
    let bigEnough = filterDirectories (>= requiredSpace) tree
21
    let bigEnough = filterDirectories (>= requiredSpace) tree
24
-   let onlySizes = map snd bigEnough
25
-   let smallest = minimum onlySizes
22
+   let smallest = minimum bigEnough
26
    putStrLn ("Smallest directory that is still large enough " ++ show smallest)
23
    putStrLn ("Smallest directory that is still large enough " ++ show smallest)
27
 
24
 

+ 25
- 24
src/Day7/Interpreter.hs View File

1
 module Day7.Interpreter (
1
 module Day7.Interpreter (
2
   buildTree,
2
   buildTree,
3
   mkdir,
3
   mkdir,
4
-  Directory (..),
4
+  FileTree (..),
5
+  Directory,
5
   calculateSize,
6
   calculateSize,
6
   filterDirectories,
7
   filterDirectories,
7
   sizeOfDirectories,
8
   sizeOfDirectories,
8
-  sumUp,
9
 ) where
9
 ) where
10
 
10
 
11
 import Day7.Parser
11
 import Day7.Parser
12
 import Data.Map (Map)
12
 import Data.Map (Map)
13
 import qualified Data.Map as Map
13
 import qualified Data.Map as Map
14
+import qualified Data.Foldable as F
14
 
15
 
15
-data Directory = Directory
16
-  { sub :: Map String Directory
17
-  , files :: Map String Int
16
+
17
+data FileTree a = FileTree
18
+  { sub :: Map String (FileTree a)
19
+  , files :: Map String a
18
   , isRoot :: Bool
20
   , isRoot :: Bool
19
 } deriving (Eq)
21
 } deriving (Eq)
20
 
22
 
23
+-- Directory is a FileTree with file sizes of Int
24
+type Directory = FileTree Int
25
+
26
+-- pretty much only useful for summing up file sizes 
27
+instance F.Foldable FileTree where
28
+  foldMap f dir = foldMap f (files dir) <> mconcat mappedSubfolders
29
+    where
30
+      subFolders = Map.elems $ sub dir
31
+      mappedSubfolders = map (foldMap f) subFolders
21
 
32
 
22
-instance Show Directory where
33
+instance Show a => Show (FileTree a) where
23
   show d = "DIR " ++ show (Map.toList $ files d) ++ " - " ++ show (Map.toList $ sub d) ++ "\n"
34
   show d = "DIR " ++ show (Map.toList $ files d) ++ " - " ++ show (Map.toList $ sub d) ++ "\n"
24
 
35
 
25
 mkdir :: Directory
36
 mkdir :: Directory
26
-mkdir = Directory { sub = Map.empty, files = Map.empty, isRoot = False }
37
+mkdir = FileTree { sub = Map.empty, files = Map.empty, isRoot = False }
27
 
38
 
28
 rootDirectory :: Directory
39
 rootDirectory :: Directory
29
 rootDirectory = mkdir { isRoot = True  }
40
 rootDirectory = mkdir { isRoot = True  }
57
 toFiles [] = []
68
 toFiles [] = []
58
 
69
 
59
 calculateSize :: Directory -> Int
70
 calculateSize :: Directory -> Int
60
-calculateSize dir = sum (Map.elems (files dir)) + sum sizes
61
-  where
62
-    subFolders = Map.elems (sub dir)
63
-    sizes = map calculateSize subFolders
71
+calculateSize = F.foldl' (+) 0
64
 
72
 
65
-flatten :: Directory -> [(String, Directory)]
66
-flatten dir = flatten' ("/", dir)
67
-  where
68
-  flatten' (name, d) = (name, d) : concatMap flatten' (Map.toList (sub d))
73
+flatten :: Directory -> [Directory]
74
+flatten d = d : concatMap flatten (Map.elems (sub d))
69
 
75
 
70
-sizeOfDirectories :: Directory -> [(String, Int)]
71
-sizeOfDirectories dir = map withSize allDirectories
72
-  where
73
-    allDirectories = flatten dir
74
-    withSize (name, directory) = (name, calculateSize directory)
76
+sizeOfDirectories :: Directory -> [Int]
77
+sizeOfDirectories = map calculateSize . flatten
75
 
78
 
76
-filterDirectories :: (Int -> Bool) -> Directory -> [(String, Int)]
77
-filterDirectories predicate dir = filter (\(_, size) -> predicate size) $ sizeOfDirectories dir
79
+filterDirectories :: (Int -> Bool) -> Directory -> [Int]
80
+filterDirectories predicate dir = filter predicate $ sizeOfDirectories dir
78
 
81
 
79
-sumUp :: [(String, Int)] -> Int
80
-sumUp = sum . map snd

+ 1
- 1
src/Day7/Parser.hs View File

18
 
18
 
19
 data TerminalCommand = In DirName | Out | Root | Listing [ListingEntry]
19
 data TerminalCommand = In DirName | Out | Root | Listing [ListingEntry]
20
  deriving (Show, Eq)
20
  deriving (Show, Eq)
21
- 
21
+
22
 parseTerminalLines :: String -> Either ParseError  [TerminalCommand]
22
 parseTerminalLines :: String -> Either ParseError  [TerminalCommand]
23
 parseTerminalLines = parse terminal "(error)"
23
 parseTerminalLines = parse terminal "(error)"
24
 
24
 

+ 1
- 1
test/Day7Spec.hs View File

126
            let parsed = forceRight $ parseTerminalLines inputPart1
126
            let parsed = forceRight $ parseTerminalLines inputPart1
127
            let tree = buildTree parsed
127
            let tree = buildTree parsed
128
            let filtered = filterDirectories (<= 100000) tree
128
            let filtered = filterDirectories (<= 100000) tree
129
-           let summed = sumUp filtered
129
+           let summed = sum filtered
130
            summed `shouldBe` 95437
130
            summed `shouldBe` 95437

Loading…
Cancel
Save