Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 哈斯克尔:列出所有的共同因素_List_Sorting_Haskell - Fatal编程技术网

List 哈斯克尔:列出所有的共同因素

List 哈斯克尔:列出所有的共同因素,list,sorting,haskell,List,Sorting,Haskell,我正在学习Haskell,目前正在创建一个程序,从3个不同的Int:s中查找所有公约数。 我有一个工作计划,但对大数字的评估时间很长。我想要关于如何优化它的建议 示例:组合查看器234944 2467444 144456==[1,2,4,8] 如前所述,我对此非常陌生,因此非常感谢您的帮助 import Data.List combineDivisors :: Int -> Int -> Int -> [Int] combineDivisors n1 n2 n3 =

我正在学习Haskell,目前正在创建一个程序,从3个不同的Int:s中查找所有公约数。 我有一个工作计划,但对大数字的评估时间很长。我想要关于如何优化它的建议

示例:
组合查看器234944 2467444 144456==[1,2,4,8]

如前所述,我对此非常陌生,因此非常感谢您的帮助

import Data.List

combineDivisors :: Int -> Int -> Int -> [Int]
combineDivisors n1 n2 n3 =
    mergeSort list
    where list = getTrips concList
          concList = isDivisor n1 ++ isDivisor n2 ++ isDivisor n3
             
isDivisor n = [x | x <- [1..n], mod n x == 0]

getTriplets :: Ord a => [a] -> [a]
getTriplets = map head . filter (\l -> length l > 2) . group . sort


--Merge sort--

split :: [a] -> ([a],[a])
split xs =
   let
     l = length xs `div` 2
   in
    (take l xs, drop l xs)

merge :: [Int] -> [Int] -> [Int]
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
   | y < x = y : merge (x:xs) ys
   | otherwise = x : merge xs (y:ys)

mergeSort :: [Int] -> [Int]
mergeSort [] = []
mergeSort [x] = [x]
mergeSort xs =
   let
     (xs1,xs2) = split xs
   in
    merge (mergeSort xs1) (mergeSort xs2)
导入数据。列表
组合查看器::Int->Int->Int->[Int]
组合式蒸发器n1 n2 n3=
合并排序列表
其中list=getTrips concList
concList=isDivisor n1++isDivisor n2++isDivisor n3
isDivisor n=[x | x[a]->[a]
getTriplets=map head.filter(\l->length l>2).group.sort
--合并排序--
拆分::[a]->([a],[a])
拆分X=
让
l=长度xs`div`2
在里面
(取左X,放下左X)
合并::[Int]->[Int]->[Int]
合并[]ys=ys
合并xs[]=xs
合并(x:xs)(y:ys)
|y[Int]
合并排序[]=[]
合并排序[x]=“x]
合并排序xs=
让
(xs1,xs2)=拆分xs
在里面
合并(合并排序xs1)(合并排序xs2)

您应该使用标准算法对其GCD进行素数分解:

导入数据。列表
导入符合条件的Data.Map.Strict作为M
--无限素数表
素数::[整数]
素数=2:3:过滤器
(\n->非$any)
(\p->n`mod`p==0)
(takeWhile(\p->p*p[Integer]
素数分解
|n p*p[a]->M.映射一个Int
getCounts[]=M.empty
getCounts(x:xs)=M.insertWith(const(+1))x1m
其中m=getCounts xs
--从计数图中获取所有可能的组合
--例如getCombos(M.fromList[('a',2),('b',1),('c',2)])
--=[,“c”,“cc”,“b”,“bc”,“bcc”,“a”,“ac”,“acc”,“ab”,“abc”,“abcc”,“aa”,“aac”,“aacc”,“aab”,“aabc”,“aabcc”]
getCombos::M.映射一个Int->[[a]]
getCombos m=allFactors
哪里
list=M.toList M
系数=fst列表
计数=snd列表
可能=(\n->[0..n])计数
allCounts=可能的序列
allFactors=(\count->concat$zipWith replicate count factors)allCounts
--获取数字列表的公因数
commonFactorsList::[Integer]->[Integer]
commonFactorsList[]=[]
commonFactorsList l=排序因子
哪里
总gcd=折叠1 gcd l
--然后得到它们的组合,并用它们的产品得到因子
factors=map product.getCombos.getCounts.primeFactorize$totalGcd
--3个数字的辅助函数
commonFactors3::Integer->Integer->Integer->[Integer]
CommonFactors 3 a b c=CommonFactors列表[a,b,c]

如果您不太关心内存使用情况,可以使用
Data.IntSet
和一个函数来查找给定数字的所有因素

首先,让我们创建一个函数,返回一个数的所有因子的
IntSet
-

import qualified Data.IntSet作为IntSet
因子::Int->IntSet.IntSet
因子n=IntSet.fromList.f$1——将因子列表转换为一个集合
哪里
--返回因子列表的实际函数
f::Int->[Int]
f i
--当i超过n的平方根时退出
|i*i>n=[]
|否则=如果n`mod`i==0
--n可被i整除-将i和n/i添加到列表中
然后i:n`div`i:f(i+1)
--n不能被i整除-继续下一步
其他f(i+1)
现在,一旦你有了对应于每个数字的
IntSet
,你只需要对它们进行一次运算就可以得到结果

commonFactors::Int->Int->Int->[Int]
公共因子n1 n2 n3=IntSet.toList$IntSet.intersection(因子n3)$IntSet.intersection(因子n1)$factors n2
这是可行的,但有点难看。制作一个可以接受多个
IntSet
s并生成最终相交结果的
intersects
函数怎么样

交叉点::[IntSet.IntSet]->IntSet.IntSet
交叉点[]=IntSet.empty
交叉点(t:ts)=foldl IntSet.intersection t ts
它应该折叠在
IntSet
s列表上,以找到最终的交点

现在您可以重构
commonFactors
以-

commonFactors::Int->Int->Int->[Int]
commonFactors n1 n2 n3=IntSet.toList.Crossons$[因子n1,因子n2,因子n3]
更好?我想是的。最后一个改进怎么样,一个通用的
commonFactors
函数,用于
n
整数量

commonFactors::[Int]->[Int]
commonFactors=IntSet.toList.Crossons.map factors
请注意,这是使用
IntSet
,因此它自然被限制为
Int
s。如果您想改用
Integer
,只需将
IntSet
替换为常规的
Set Integer

输出 公共因素[23494424674144456] [1,2,4,8]
Function
isdivisior
的名称似乎暗示它返回一个布尔值。最好使用
divisiorList
也许更好。效率:您可以从将数字分解为素数的幂开始。请参阅关于素数的说明。