我是Haskell的新手,并试图实现一些遗传算法。 目前,我没有选择个人列表中的n个最佳元素(每个人都是自己的列表)。 个人创建如下:
ind1 :: [Int]
ind1 = [1, 1, 1, 1, 1, 1, 1]
ind2 :: [Int]
ind2 = [0, 0, 0, 0, 0, 0, 0]
适当的人口包括这些人的名单:
pop :: [[Int]]
pop = [ind1, ind2]
我想要达到的目标是获得群体中最好的n个人,其中“最佳”由其元素的总和决定,例如,
> sum ind1
7
> sum ind2
0
我开始创建一个用于创建具有个性及其质量的元组的函数:
f x = [(ind, sum ind) | ind <- x]
所以至少我得到了这样的东西:
[([1, 1, 1, 1, 1, 1, 1], 7), ([0, 0, 0, 0, 0, 0, 0], 0)]
如何从此处获得预期结果?我甚至无法获得“snd == max”中元组的“fst”。 我从不同主题中看到的递归方法开始,但遗憾的是没有合理的结果。 任何建议,可能也在哪里阅读? 谢谢!
答案 0 :(得分:4)
答案 1 :(得分:4)
此处的最佳选择是使用sortBy
中的Data.List
:
sortBy :: (a -> a -> Ordering) -> [a] -> [a]
sortBy
函数是高阶函数,因此它将函数作为其参数之一。它需要的功能是获取两个元素并返回Ordering
值(LT
,EQ
或GT
)的函数。您可以编写自己的自定义比较函数,但Data.Ord
模块有comparing
,它有助于编写这些比较函数:
comparing :: Ord b => (a -> b) -> (a -> a -> Ordering)
希望你能看到comparing
如何与sortBy
配对,你传递一个函数将你的类型转换为已知的可比类型,然后你有一个正确类型的函数传递给{ {1}}。所以在实践中你可以做到
sortBy
import Data.List (sortBy)
import Data.Ord (comparing)
-- Some types to make things more readable
type Individual = [Int]
type Fitness = Int
-- Here's our fitness function (change as needed)
fitness :: Individual -> Fitness
fitness = sum
-- Redefining so it can be used with `map`
f :: Individual -> (Individual, Fitness)
f ind = (ind, fitness ind)
-- If you do want to see the fitness of the top n individuals
solution1 :: Int -> [Individual] -> [(Individual, Fitness)]
solution1 n inds = take n $ sortBy (flip $ comparing snd) $ map f inds
-- If you just want the top n individuals
solution2 :: Int -> [Individual] -> [Individual]
solution2 n inds = take n $ sortBy (flip $ comparing fitness) inds
参数中的flip
强制排序降序而不是默认升序,因此从sortBy
返回的第一个n
值将是{ {1}}具有最高适应度的值,按降序排列。如果您想尝试不同的健身功能,那么您可以执行类似
sortBy
然后你有
n
但你也可以
fittestBy :: (Individual -> Fitness) -> Int -> [Individual] -> [Individual]
fittestBy fit n = take n . sortBy (flip $ comparing fit)
如果你想将你的适应度函数改为产品而不是总和。