我对这种语言还很陌生,所以我很难找到解决问题的最佳方法。我想获取Point
的列表,例如[(1,0),(2,3),(4,6)]
,并确定最小和最大x
和y
值,因为我需要使用它们构建网格。
这是我的代码:
type Point a = (a,a)
-- The main program: read points from stdin, write an SVG file to stdout.
main :: IO ()
main = do
str <- getContents
let points = toPoints str
let minXY = [(x,y) | x <- points, y <- points, x1 <- points, y1 <- points, x < x1, y < y1]
mapM_ (mapM_ print) minXY
答案 0 :(得分:2)
您可以使用x
函数将点列表分区为y
和unzip
坐标列表,该函数将对列表转换为一对列表:
unzip :: [(a, b)] -> ([a], [b])
points = [(1,0),(2,3),(4,6)]
unzip points = ([1,2,4],[0,3,6])
然后,您可以使用minimum
和maximum
函数直接计算每个列表的最小值和最大值:
bounds :: [Point Int] -> ((Int, Int), (Int, Int))
bounds points = ((minimum xs, maximum xs), (minimum ys, maximum ys))
where (xs, ys) = unzip points
只是为了好玩,这是一个更先进的解决方案,只能在坐标上进行一次传递:
import Control.Arrow
import Data.Semigroup
bounds = unzip >>> minmax *** minmax
where minmax = foldMap (Min &&& Max) >>> getMin *** getMax
它使用了Control.Arrow
中的一些便捷操作符:
-- Apply two functions to a single value, returning both results.
(f &&& g) x = (f x, g x)
-- Apply two functions to the elements of a pair.
(f *** g) (x, y) = (f x, g y)
-- Left-to-right function composition.
(f >>> g) x = g (f x)
以及来自Min
的{{1}}和Max
幺半群:
Data.Semigroup
答案 1 :(得分:1)
您可以使用前奏中的minimum
和maximum
来计算数字列表的最小值和最大值。在调用之前,我们需要使用fst将元组列表映射到数字列表中,fst获取元组或snd的第一项以获取元组的第二项。
获取x
maximum $ fst <$> [(1,0),(2,3),(4,6)]
同样的事情,y
使用snd
代替fst
答案 2 :(得分:1)
@gabesoft解决方案是这样做的一种方式。以下将计算每轴单次通过的最小值和最大值。 让我们定义一个函数,它接受一个表示当前结果的元组(累加器或最小值和最大值),一个值为a,并将新结果作为元组返回。
minMax :: (Ord a) => (a, a) -> a -> (a, a)
minMax (minAcc, maxAcc) val = (min minAcc val, max maxAcc val)
我们现在可以在折叠中使用此功能:
points = [(1,2), (3, 4), (-1, -3)] :: [(Int, Int)]
foldl minMax (maxBound, minBound) points
我们使用maxBound / minBound来获取Int的最小/最大边界作为起始值。 但是,这不适用于元组列表。要使它在元组上工作,您可以执行以下操作:
foldl minMax (maxBound::Int, minBound::Int) $ fst <$> points
foldl minMax (maxBound::Int, minBound::Int) $ snd <$> points
<$>
运算符为fmap
。因此,我们首先在点上运行fst
以提取第一个元组值,并使用折叠将minMax
函数应用于此。