如何为多个数字生成有序倍数列表?Haskell作业求助
解决Haskell中合并多个整数倍数有序列表的问题
嘿,我明白你现在遇到的问题了——你已经搞定了单个整数的无限倍数列表,现在要扩展成处理多个因子,并且输出有序且无重复的倍数列表对吧?你之前用的列表推导式之所以输出无序的结果,是因为它先把每个y对应的所有因子的倍数都列出来了(比如y=1时先出3、5,y=2时出6、10),而不是按全局大小排序。
下面给你两种可行的方案,其中第一种就用到了你提到的取模函数提示:
方案一:筛选法(利用取模判断整除)
这个思路很直接:生成所有正整数,然后筛选出能被列表中任意一个因子整除的数。代码实现如下:
function :: [Int] -> [Int] function ds = [n | n <- [1..], any (\d -> n `mod` d == 0) ds]
解释:
n <- [1..]生成无限的正整数序列any (\d -> nmodd == 0) ds检查当前n是否能被ds中的至少一个因子整除:nmodd == 0就是判断n是d的倍数的核心条件,any函数只要有一个d满足条件就返回True- 测试一下:
take 10 (function [3,5])会返回[3,5,6,9,10,12,15,18,20,21],完全符合你的需求!
这种方法的优点是简单直观,容易理解;缺点是如果因子列表ds很大,或者因子本身很大,效率会稍低,因为每个n都要遍历所有因子检查整除性。
方案二:合并有序子列表(更高效的方式)
既然每个单个因子的倍数列表都是有序的(比如function 3是[3,6,9,...],function 5是[5,10,15,...]),我们可以把这些有序列表合并成一个全局有序且无重复的列表。
首先实现两个有序列表的合并函数(带去重):
merge :: Ord a => [a] -> [a] -> [a] merge [] ys = ys merge xs [] = xs merge (x:xs) (y:ys) | x < y = x : merge xs (y:ys) | x > y = y : merge (x:xs) ys | otherwise = x : merge xs ys -- 遇到重复元素只保留一个
然后实现合并多个有序列表的函数:
mergeAll :: Ord a => [[a]] -> [a] mergeAll [] = [] mergeAll (x:xs) = merge x (mergeAll xs)
最后,你的目标函数可以写成:
function :: [Int] -> [Int] function ds = mergeAll [map (*d) [1..] | d <- ds]
解释:
[map (*d) [1..] | d <- ds]先生成每个因子对应的无限倍数列表mergeAll把这些有序列表逐步合并成一个全局有序的列表,同时自动去重- 测试同样会得到正确的结果,而且这种方法的效率更高,因为它利用了子列表有序的特性,不需要逐个检查每个数。
为什么你之前的列表推导式不行?
你写的 [y*x | y <- [1..], x <- d] 是先遍历y的每个值,再遍历d中的每个因子,所以生成的顺序是:
y=1时:31,51 → [3,5]
y=2时:32,52 → [6,10]
y=3时:33,53 → [9,15]
...
这样拼接起来的列表自然是[3,5,6,10,9,15,...],不是全局有序的,这就是问题所在。
内容的提问来源于stack exchange,提问作者csstudent
相关产品推荐
相关产品推荐

