Skip to content

Commit 80dc0e0

Browse files
authored
Fix ch4 largestSmallest (#225)
* Make chapter4 largestSmallest solution and test use Array Path * Update instructions for largestSmallest and change difficulty * Swap largestSmallest and whereIs test/solution order to reflect instructions * Expand on smallestLargest instructions * Fix instruction grammar * Simplify root test case * Add single file dir and empty dir test cases * Remove now unused imports * Make note style consistent with other examples
1 parent a850ae5 commit 80dc0e0

File tree

4 files changed

+36
-30
lines changed

4 files changed

+36
-30
lines changed

exercises/chapter4/src/Data/Path.purs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module Data.Path
2-
( Path()
2+
( Path(..)
33
, root
44
, ls
55
, filename

exercises/chapter4/test/Main.purs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import Test.MySolutions
66
import Test.NoPeeking.Solutions -- Note to reader: Delete this line
77
import Data.Array (sort)
88
import Data.Maybe (Maybe(..))
9-
import Data.Path (filename, root)
9+
import Data.Path (Path(..), filename, root)
1010
import Data.Tuple (fst)
1111
import Effect (Effect)
1212
import Test.Unit (TestSuite, suite, test)
@@ -155,10 +155,6 @@ Note to reader: Delete this line to expand comment block -}
155155
]
156156
$ map filename
157157
$ onlyFiles root
158-
test "Exercise - largestSmallest for root" do
159-
Assert.equal [ "/home/user/code/js/test.js", "/etc/hosts" ]
160-
$ map fst
161-
$ largestSmallest root
162158
suite "Exercise - whereIs" do
163159
test "locates a file"
164160
$ Assert.equal (Just ("/bin/"))
@@ -168,6 +164,21 @@ Note to reader: Delete this line to expand comment block -}
168164
$ Assert.equal (Nothing)
169165
$ map filename
170166
$ whereIs root "cat"
167+
suite "Exercise - largestSmallest" do
168+
let
169+
testls :: String -> Array String -> Path -> TestSuite
170+
testls label expected path =
171+
test label do
172+
Assert.equal expected
173+
-- Sorting to allow any ordering
174+
$ sort
175+
$ map filename
176+
$ largestSmallest path
177+
oneFileDir = Directory "/etc/" [ File "/etc/hosts" 300 ]
178+
emptyDir = Directory "/etc/" []
179+
testls "works for root" ["/etc/hosts", "/home/user/code/js/test.js"] root
180+
testls "works for a directory with one file" ["/etc/hosts"] oneFileDir
181+
testls "works for an empty directory" [] emptyDir
171182

172183
{- Note to reader: Delete this line to expand comment block
173184
-}

exercises/chapter4/test/no-peeking/Solutions.purs

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module Test.NoPeeking.Solutions where
22

33
import Prelude
44
import Control.MonadZero (guard)
5-
import Data.Array (cons, filter, head, last, length, tail, (..))
5+
import Data.Array (catMaybes, cons, filter, find, head, last, length, nub, tail, (..))
66
import Data.Foldable (foldl)
77
import Data.Int (rem, quot)
88
import Data.Maybe (Maybe(..), fromMaybe, maybe)
@@ -97,27 +97,6 @@ reverse = foldl (\xs x -> [ x ] <> xs) []
9797
onlyFiles :: Path -> Array Path
9898
onlyFiles p = filter (\p' -> not $ isDirectory p') $ allFiles p
9999

100-
maxSigned32BitInt :: Int
101-
maxSigned32BitInt = 2147483647
102-
103-
largestSmallest :: Path -> Array (Tuple String Int)
104-
largestSmallest path = largestSmallestPaths (allFiles path)
105-
where
106-
largestSmallestPaths :: Array Path -> Array (Tuple String Int)
107-
largestSmallestPaths paths = [ outlier (\i j -> i > j) 0 paths, outlier (\i j -> i < j) maxSigned32BitInt paths ]
108-
where
109-
outlier :: (Int -> Int -> Boolean) -> Int -> Array Path -> Tuple String Int
110-
outlier criteria startValue paths' =
111-
foldl
112-
( \acc p' ->
113-
( case size p' of
114-
Just n -> if criteria n $ snd acc then Tuple (filename p') n else acc
115-
Nothing -> acc
116-
)
117-
)
118-
(Tuple "" startValue)
119-
paths'
120-
121100
allSizes :: Array Path -> Array (Tuple String Int)
122101
allSizes paths =
123102
map
@@ -136,3 +115,19 @@ whereIs path fileName = head $ whereIs' $ allFiles path
136115
child <- ls path
137116
guard $ eq fileName $ fromMaybe "" $ last $ split (Pattern "/") $ filename child
138117
pure path
118+
119+
largestSmallest :: Path -> Array Path
120+
largestSmallest path =
121+
let files = onlyFiles path
122+
maybeSizes = map size files
123+
maybeMax = foldl (outlier (>)) Nothing maybeSizes
124+
maybeMin = foldl (outlier (<)) Nothing maybeSizes
125+
in catMaybes $ map (findFileBySize files) $ nub $ [maybeMax, maybeMin]
126+
where
127+
outlier :: (Int -> Int -> Boolean) -> Maybe Int -> Maybe Int -> Maybe Int
128+
outlier criteria Nothing Nothing = Nothing
129+
outlier criteria (Just x) Nothing = Just x
130+
outlier criteria Nothing (Just x) = Just x
131+
outlier criteria (Just x1) (Just x2) = if criteria x1 x2 then Just x1 else Just x2
132+
findFileBySize :: Array Path -> Maybe Int -> Maybe Path
133+
findFileBySize files maybeSize = find (\file -> size file == maybeSize) files

text/chapter4.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,7 @@ Try out the new version in PSCi - you should get the same result. I'll let you d
643643
## Exercises
644644

645645
1. (Easy) Write a function `onlyFiles` which returns all _files_ (not directories) in all subdirectories of a directory.
646-
1. (Medium) Write a function `largestSmallest` which returns an array containing the single largest and single smallest files in the filesystem.
647-
1. (Difficult) Write a function `whereIs` to search for a file by name. The function should return a value of type `Maybe Path`, indicating the directory containing the file, if it exists. It should behave as follows:
646+
2. (Medium) Write a function `whereIs` to search for a file by name. The function should return a value of type `Maybe Path`, indicating the directory containing the file, if it exists. It should behave as follows:
648647

649648
```text
650649
> whereIs root "ls"
@@ -655,6 +654,7 @@ Try out the new version in PSCi - you should get the same result. I'll let you d
655654
```
656655
657656
_Hint_: Try to write this function as an array comprehension using do notation.
657+
3. (Difficult) Write a function `largestSmallest` which takes a `Path` and returns an array containing the single largest and single smallest files in the `Path`. _Note_: consider the cases where there are zero or one files in the `Path` by returning an empty array or a one-element array respectively.
658658
659659
## Conclusion
660660

0 commit comments

Comments
 (0)