此函数返回一个包含列表最小值和最大值的2元组:
import Control.Arrow ((***), (>>>), (&&&))
import Data.Semigroup (getMin, getMax, Min(..), Max(..))
bounds :: (Bounded a, Ord a) => [a] -> (a,a)
bounds = foldMap (Min &&& Max) >>> getMin *** getMax
示例:
> x = [1..10 :: Int]
> bounds x
(1,10)
它比(minimum x, maximum x)
更有效吗?
还是有另一种方法比(minimum x, maximum x)
更有效吗?
答案 0 :(得分:11)
首先,你的两个功能表现不一样。当(minimum xs, maximum xs)
是一个空列表时,xs
就会死亡。
它比
(minimum x, maximum x)
更有效吗?
他们都是O(n),但回答这类问题的唯一方法就是以竞争方式对他们进行基准测试。我认为我希望foldMap
解决方案更快,因为它只会对列表进行一次传递,但让我们找出答案。
import Control.Arrow ((***), (>>>), (&&&))
import Data.Semigroup (getMin, getMax, Min(..), Max(..))
import System.Random
import Criterion.Main
bounds1, bounds2 :: (Bounded a, Ord a) => [a] -> (a,a)
bounds1 = foldMap (Min &&& Max) >>> getMin *** getMax
bounds2 xs = (minimum xs, maximum xs)
randomList :: Int -> IO [Int]
randomList count = take count <$> randoms <$> newStdGen
mkBench n = env (randomList n) $ \list -> bgroup (show n) [
bench "foldMap" $ nf bounds1 list,
bench "minMax" $ nf bounds2 list
]
main = defaultMain $ map mkBench [100, 1000, 10000, 100000, 1000000]
列表,那是
100/foldMap 1.411 μs
100/minMax 517.6 ns
1000/foldMap 28.94 μs
1000/minMax 5.078 μs
10000/foldMap 488.4 μs
10000/minMax 51.56 μs
100000/foldMap 21.08 ms
100000/minMax 537.3 μs
1000000/foldMap 268.9 ms
1000000/minMax 8.989 ms
所以(minimum xs, maximum xs)
的结果比foldMap
更快。