如何改进这个Haskell组合算法?

时间:2015-10-09 22:04:04

标签: haskell ghc

下面介绍的解决方案如何改进以下问题?它能在时间和空间上更有效吗?是否有空间泄漏?

问题: 给定Astronauts的输入列表,生成Astronauts对的列表,使得这些对没有来自同一国家/地区的两个Astronauts。假设输入的列表Astronauts具有唯一identifier s。

data Astronaut = Astronaut { identifier :: Int, country :: String } deriving (Eq)

astronautPairs :: [Astronaut] -> [(Astronaut, Astronaut)]
astronautPairs xs = foldl accumulatePairs [] [(a, b) | a <- xs, b <- xs, country a /= country b]
    where
        accumulatePairs pairs pair = if hasPair pair pairs then pairs else pair:pairs
        hasPair pair@(a,b) ((c,d):xs) = a == d && b == c || hasPair pair xs
        hasPair _ [] = False

2 个答案:

答案 0 :(得分:2)

而不是消除翻转对,为什么不首先避免生成它们。是我们生产它们,是吗?

import Data.List (tails)

astronautPairs :: [Astronaut] -> [(Astronaut, Astronaut)]
astronautPairs xs = [ (y,z) | (y:ys) <- tails xs, z <- .... , country y /= country .... ]

这假定宇航员的输入列表没有重复。

因此,我们通过三角形生成来避免重复。

(我留下了部分代码,供您完成)。

答案 1 :(得分:0)

让我们从实施细节中退一步,思考一下你想要实现的目标:

  

生成Astronaut对的列表,以使这些对没有来自同一个国家/地区的两个Astronaut

您似乎可以假设每个宇航员只在列表中出现一次。

解决此问题的一种有效方法是首先按国家分区列表。一种自然的方法是建立一个HashMap String [Int],其中包含来自每个国家的所有宇航员的清单。

import qualified Data.HashMap.Strict as HMS
import Data.HashMap.Strict (HashMap)

divideAstronauts :: [Astronaut] -> HashMap String [Int]
divideAstronauts = foldl' go mempty where
  go hm (Astronaut ident cntry) = HMS.insertWith (++) cntry [ident] hm

现在,您可以将程序的其余部分分为两个步骤:

  1. 选择所有国家/地区。
  2. 对于每对国家,选择所有宇航员对,每个宇航员来自其中一个国家。