这个Haskell组合算法如何改进?
How can this Haskell combination algorithm be improved?
如何改进下面提出的针对以下问题的解决方案?能不能在时间和space上更有效率?有 space 泄漏吗?
问题:
给定 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
让我们从实施细节退一步,想想您要实现的目标:
produce a list of pairs of Astronaut
s such that the pairs do not have two Astronaut
s from the same country
你似乎被允许假设每个宇航员在列表中只出现一次。
解决此问题的一种有效方法是首先按国家 划分列表。一个自然的方法是构建一个 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
现在您可以将程序的其余部分分为两步:
- 选择所有国家对。
- 对于每一对国家,选择所有宇航员对,使每个宇航员都来自其中一个国家。
为什么不首先避免生成翻转对,而不是消除翻转对。是我们生产的,对吧?
import Data.List (tails)
astronautPairs :: [Astronaut] -> [(Astronaut, Astronaut)]
astronautPairs xs = [ (y,z) | (y:ys) <- tails xs, z <- .... , country y /= country .... ]
这里假设宇航员的输入列表没有重复项。
因此,我们避免了三角生成的重复。
(我留了一部分代码,你自己补)
如何改进下面提出的针对以下问题的解决方案?能不能在时间和space上更有效率?有 space 泄漏吗?
问题:
给定 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
让我们从实施细节退一步,想想您要实现的目标:
produce a list of pairs of
Astronaut
s such that the pairs do not have twoAstronaut
s from the same country
你似乎被允许假设每个宇航员在列表中只出现一次。
解决此问题的一种有效方法是首先按国家 划分列表。一个自然的方法是构建一个 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
现在您可以将程序的其余部分分为两步:
- 选择所有国家对。
- 对于每一对国家,选择所有宇航员对,使每个宇航员都来自其中一个国家。
为什么不首先避免生成翻转对,而不是消除翻转对。是我们生产的,对吧?
import Data.List (tails)
astronautPairs :: [Astronaut] -> [(Astronaut, Astronaut)]
astronautPairs xs = [ (y,z) | (y:ys) <- tails xs, z <- .... , country y /= country .... ]
这里假设宇航员的输入列表没有重复项。
因此,我们避免了三角生成的重复。
(我留了一部分代码,你自己补)