我是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”。我从在不同主题中看到的递归方法开始,但是不幸的是没有合理的结果。有什么建议,可能还在哪里阅读?谢谢!
这里最好的选择是使用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
,并向其传递一个将您的类型转换为已知的可比较类型的函数,然后又有一个正确类型的函数传递给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
参数中的insortBy
强制排序为降序而不是默认的升序,因此n
从返回的第一个值sortBy
将是n
适应性最高的值(降序排列)。如果您想尝试不同的健身功能,则可以执行以下操作
fittestBy :: (Individual -> Fitness) -> Int -> [Individual] -> [Individual]
fittestBy fit n = take n . sortBy (flip $ comparing fit)
那你有
solution2 = fittestBy sum
但是你也可以
solution3 = fittestBy product
如果您想将健身功能更改为乘积而不是总和。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句