Day 7 - Foldable instance for summing up directories

This commit is contained in:
Jens Kadenbach
2022-12-07 18:14:05 +01:00
parent 7f4a4329b0
commit 435a06fd59
4 changed files with 30 additions and 32 deletions

View File

@@ -13,15 +13,12 @@ day7 = do
let parsed = forceRight $ parseTerminalLines input
let tree = buildTree parsed
let small = filterDirectories (<= 100000) tree
let sumOfSmall = sumUp small
let sumOfSmall = sum small
putStrLn ("Sum of those directories is " ++ show sumOfSmall)
let rootSize = snd . head $ sizeOfDirectories tree
putStrLn ("Root size is " ++ show rootSize)
let rootSize = head $ sizeOfDirectories tree
let freeSpace = 70000000 - rootSize
let requiredSpace = 30000000 - freeSpace
putStrLn ("Required space is " ++ show requiredSpace)
let bigEnough = filterDirectories (>= requiredSpace) tree
let onlySizes = map snd bigEnough
let smallest = minimum onlySizes
let smallest = minimum bigEnough
putStrLn ("Smallest directory that is still large enough " ++ show smallest)

View File

@@ -1,29 +1,40 @@
module Day7.Interpreter (
buildTree,
mkdir,
Directory (..),
FileTree (..),
Directory,
calculateSize,
filterDirectories,
sizeOfDirectories,
sumUp,
) where
import Day7.Parser
import Data.Map (Map)
import qualified Data.Map as Map
import qualified Data.Foldable as F
data Directory = Directory
{ sub :: Map String Directory
, files :: Map String Int
data FileTree a = FileTree
{ sub :: Map String (FileTree a)
, files :: Map String a
, isRoot :: Bool
} deriving (Eq)
-- Directory is a FileTree with file sizes of Int
type Directory = FileTree Int
instance Show Directory where
-- pretty much only useful for summing up file sizes
instance F.Foldable FileTree where
foldMap f dir = foldMap f (files dir) <> mconcat mappedSubfolders
where
subFolders = Map.elems $ sub dir
mappedSubfolders = map (foldMap f) subFolders
instance Show a => Show (FileTree a) where
show d = "DIR " ++ show (Map.toList $ files d) ++ " - " ++ show (Map.toList $ sub d) ++ "\n"
mkdir :: Directory
mkdir = Directory { sub = Map.empty, files = Map.empty, isRoot = False }
mkdir = FileTree { sub = Map.empty, files = Map.empty, isRoot = False }
rootDirectory :: Directory
rootDirectory = mkdir { isRoot = True }
@@ -57,24 +68,14 @@ toFiles (_:rest) = toFiles rest
toFiles [] = []
calculateSize :: Directory -> Int
calculateSize dir = sum (Map.elems (files dir)) + sum sizes
where
subFolders = Map.elems (sub dir)
sizes = map calculateSize subFolders
calculateSize = F.foldl' (+) 0
flatten :: Directory -> [(String, Directory)]
flatten dir = flatten' ("/", dir)
where
flatten' (name, d) = (name, d) : concatMap flatten' (Map.toList (sub d))
flatten :: Directory -> [Directory]
flatten d = d : concatMap flatten (Map.elems (sub d))
sizeOfDirectories :: Directory -> [(String, Int)]
sizeOfDirectories dir = map withSize allDirectories
where
allDirectories = flatten dir
withSize (name, directory) = (name, calculateSize directory)
sizeOfDirectories :: Directory -> [Int]
sizeOfDirectories = map calculateSize . flatten
filterDirectories :: (Int -> Bool) -> Directory -> [(String, Int)]
filterDirectories predicate dir = filter (\(_, size) -> predicate size) $ sizeOfDirectories dir
filterDirectories :: (Int -> Bool) -> Directory -> [Int]
filterDirectories predicate dir = filter predicate $ sizeOfDirectories dir
sumUp :: [(String, Int)] -> Int
sumUp = sum . map snd

View File

@@ -18,7 +18,7 @@ data ListingEntry = DirListing DirName | FileListing FileName Size
data TerminalCommand = In DirName | Out | Root | Listing [ListingEntry]
deriving (Show, Eq)
parseTerminalLines :: String -> Either ParseError [TerminalCommand]
parseTerminalLines = parse terminal "(error)"

View File

@@ -126,5 +126,5 @@ spec =
let parsed = forceRight $ parseTerminalLines inputPart1
let tree = buildTree parsed
let filtered = filterDirectories (<= 100000) tree
let summed = sumUp filtered
let summed = sum filtered
summed `shouldBe` 95437