Preliminary notes
I study Haskell.
A question , which I answered a few days ago, gave me inspiration for this exercise in Haskell, which made it possible to experiment with several things, still found out, and also left me questions :)
Problem Statement
For a rectangle A of width wand height, hfind the best rectangle B that matches ntimes within A , where best means the smallest perimeter.
My attempt
I started with the basic idea of ββcreating a set of sub-rectangles A having an area equal to div (w * h) n, and then choosing the one that has the smallest perimeter.
Here are three implementations of this idea that I came up with; they are in chronological order: I got inspiration for the third after I made the second, which I got after I made the first (OK, there is version 0 in which I did not use data Rectangle, but just a tuple (x, y)):
Implementation 1
data Rectangle = Rectangle { width :: Integer,
height :: Integer
} deriving (Show)
subRectangles :: Rectangle -> Integer -> [ Rectangle ]
subRectangles r n = [ Rectangle x y | x <- [1..w ], y <- [1..h], x * y == (w * h) `div` n ]
where w = width r
h = height r
bestSubRectangle :: [ Rectangle ] -> Rectangle
bestSubRectangle [ r ] = r
bestSubRectangle (r:rs)
| perimeter r < perimeter bestOfRest = r
| otherwise = bestOfRest
where bestOfRest = bestSubRectangle rs
perimeter :: Rectangle -> Integer
perimeter r = (width r) + (height r)
Implementation 2
data Rectangle = Rectangle { width :: Integer,
height :: Integer
} deriving (Show)
subRectangles :: Rectangle -> Integer -> [ Rectangle ]
subRectangles r n = [ Rectangle x y | x <- [1..w ], y <- [1..h], x * y == (w * h) `div` n ]
where w = width r
h = height r
bestSubRectangle :: [ Rectangle ] -> Rectangle
bestSubRectangle xs = foldr smaller (last xs) xs
smaller :: Rectangle -> Rectangle -> Rectangle
smaller r1 r2
| perimeter r1 < perimeter r2 = r1
| otherwise = r2
perimeter :: Rectangle -> Integer
perimeter r = (width r) + (height r)
Implementation 3
import Data.List
data Rectangle = Rectangle { width :: Integer,
height :: Integer
} deriving (Show, Eq)
instance Ord Rectangle where
(Rectangle w1 h1) `compare` (Rectangle w2 h2) = (w1 + h1) `compare` (w2 + h2)
subRectangles :: Rectangle -> Integer -> [ Rectangle ]
subRectangles r n = [ Rectangle x y | x <- [1..w ], y <- [1..h], x * y == (w * h) `div` n ]
where w = width r
h = height r
bestSubRectangle :: [ Rectangle ] -> Rectangle
bestSubRectangle = head . sort
Questions
Which approach is more idiomatic?
? bestSubRectangle 3 sort, O (n lg n), 1, 2 bestSubRectangle , subRectangles, O (n), , , lack- Haskell bestSubRectangle = head . sort: sort , head (head (x:_) = x)?
3 Rectangle Ord Ord? Rectangle Ord?
/ .