“同时”列表的最小值和最大值

时间:2018-04-23 23:44:49

标签: haskell

此函数返回一个包含列表最小值和最大值的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)更有效吗?

1 个答案:

答案 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]

enter image description here

列表,那是

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更快。