Day 7 - Foldable instance for summing up directories
This commit is contained in:
@@ -13,15 +13,12 @@ day7 = do
|
|||||||
let parsed = forceRight $ parseTerminalLines input
|
let parsed = forceRight $ parseTerminalLines input
|
||||||
let tree = buildTree parsed
|
let tree = buildTree parsed
|
||||||
let small = filterDirectories (<= 100000) tree
|
let small = filterDirectories (<= 100000) tree
|
||||||
let sumOfSmall = sumUp small
|
let sumOfSmall = sum small
|
||||||
putStrLn ("Sum of those directories is " ++ show sumOfSmall)
|
putStrLn ("Sum of those directories is " ++ show sumOfSmall)
|
||||||
let rootSize = snd . head $ sizeOfDirectories tree
|
let rootSize = head $ sizeOfDirectories tree
|
||||||
putStrLn ("Root size is " ++ show rootSize)
|
|
||||||
let freeSpace = 70000000 - rootSize
|
let freeSpace = 70000000 - rootSize
|
||||||
let requiredSpace = 30000000 - freeSpace
|
let requiredSpace = 30000000 - freeSpace
|
||||||
putStrLn ("Required space is " ++ show requiredSpace)
|
|
||||||
let bigEnough = filterDirectories (>= requiredSpace) tree
|
let bigEnough = filterDirectories (>= requiredSpace) tree
|
||||||
let onlySizes = map snd bigEnough
|
let smallest = minimum bigEnough
|
||||||
let smallest = minimum onlySizes
|
|
||||||
putStrLn ("Smallest directory that is still large enough " ++ show smallest)
|
putStrLn ("Smallest directory that is still large enough " ++ show smallest)
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,40 @@
|
|||||||
module Day7.Interpreter (
|
module Day7.Interpreter (
|
||||||
buildTree,
|
buildTree,
|
||||||
mkdir,
|
mkdir,
|
||||||
Directory (..),
|
FileTree (..),
|
||||||
|
Directory,
|
||||||
calculateSize,
|
calculateSize,
|
||||||
filterDirectories,
|
filterDirectories,
|
||||||
sizeOfDirectories,
|
sizeOfDirectories,
|
||||||
sumUp,
|
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Day7.Parser
|
import Day7.Parser
|
||||||
import Data.Map (Map)
|
import Data.Map (Map)
|
||||||
import qualified Data.Map as Map
|
import qualified Data.Map as Map
|
||||||
|
import qualified Data.Foldable as F
|
||||||
|
|
||||||
data Directory = Directory
|
|
||||||
{ sub :: Map String Directory
|
data FileTree a = FileTree
|
||||||
, files :: Map String Int
|
{ sub :: Map String (FileTree a)
|
||||||
|
, files :: Map String a
|
||||||
, isRoot :: Bool
|
, isRoot :: Bool
|
||||||
} deriving (Eq)
|
} 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"
|
show d = "DIR " ++ show (Map.toList $ files d) ++ " - " ++ show (Map.toList $ sub d) ++ "\n"
|
||||||
|
|
||||||
mkdir :: Directory
|
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 :: Directory
|
||||||
rootDirectory = mkdir { isRoot = True }
|
rootDirectory = mkdir { isRoot = True }
|
||||||
@@ -57,24 +68,14 @@ toFiles (_:rest) = toFiles rest
|
|||||||
toFiles [] = []
|
toFiles [] = []
|
||||||
|
|
||||||
calculateSize :: Directory -> Int
|
calculateSize :: Directory -> Int
|
||||||
calculateSize dir = sum (Map.elems (files dir)) + sum sizes
|
calculateSize = F.foldl' (+) 0
|
||||||
where
|
|
||||||
subFolders = Map.elems (sub dir)
|
|
||||||
sizes = map calculateSize subFolders
|
|
||||||
|
|
||||||
flatten :: Directory -> [(String, Directory)]
|
flatten :: Directory -> [Directory]
|
||||||
flatten dir = flatten' ("/", dir)
|
flatten d = d : concatMap flatten (Map.elems (sub d))
|
||||||
where
|
|
||||||
flatten' (name, d) = (name, d) : concatMap flatten' (Map.toList (sub d))
|
|
||||||
|
|
||||||
sizeOfDirectories :: Directory -> [(String, Int)]
|
sizeOfDirectories :: Directory -> [Int]
|
||||||
sizeOfDirectories dir = map withSize allDirectories
|
sizeOfDirectories = map calculateSize . flatten
|
||||||
where
|
|
||||||
allDirectories = flatten dir
|
|
||||||
withSize (name, directory) = (name, calculateSize directory)
|
|
||||||
|
|
||||||
filterDirectories :: (Int -> Bool) -> Directory -> [(String, Int)]
|
filterDirectories :: (Int -> Bool) -> Directory -> [Int]
|
||||||
filterDirectories predicate dir = filter (\(_, size) -> predicate size) $ sizeOfDirectories dir
|
filterDirectories predicate dir = filter predicate $ sizeOfDirectories dir
|
||||||
|
|
||||||
sumUp :: [(String, Int)] -> Int
|
|
||||||
sumUp = sum . map snd
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ data ListingEntry = DirListing DirName | FileListing FileName Size
|
|||||||
|
|
||||||
data TerminalCommand = In DirName | Out | Root | Listing [ListingEntry]
|
data TerminalCommand = In DirName | Out | Root | Listing [ListingEntry]
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq)
|
||||||
|
|
||||||
parseTerminalLines :: String -> Either ParseError [TerminalCommand]
|
parseTerminalLines :: String -> Either ParseError [TerminalCommand]
|
||||||
parseTerminalLines = parse terminal "(error)"
|
parseTerminalLines = parse terminal "(error)"
|
||||||
|
|
||||||
|
|||||||
@@ -126,5 +126,5 @@ spec =
|
|||||||
let parsed = forceRight $ parseTerminalLines inputPart1
|
let parsed = forceRight $ parseTerminalLines inputPart1
|
||||||
let tree = buildTree parsed
|
let tree = buildTree parsed
|
||||||
let filtered = filterDirectories (<= 100000) tree
|
let filtered = filterDirectories (<= 100000) tree
|
||||||
let summed = sumUp filtered
|
let summed = sum filtered
|
||||||
summed `shouldBe` 95437
|
summed `shouldBe` 95437
|
||||||
|
|||||||
Reference in New Issue
Block a user