简体   繁体   English

结合两个列表理解Haskell

[英]Combining two list comprehensions Haskell

I'm trying to calculate the first triangle number with 501 divisorsin Haskell. 我正在尝试使用Haskell中的501除数来计算第一个三角形数。 I already made two list comprehensions, one listing all the triangle numbers and one listing all divisors of a given number. 我已经做了两个列表推导,一个列出了所有三角形数字,一个列出了给定数字的所有除数。 Now I want to make one big list with all values divisors of each triangle number. 现在,我要列出一个包含每个三角形数字的所有值除数的大列表。 (eg [[1],[1,3],[1,2,3,6],[1,2,5,10] etc..) (例如[[1],[1,3],[1,2,3,6],[1,2,5,10]等。)

How can I use my triangleNumbers list in my divisors list? 如何使用除数列表中的triangleNumbers列表? My code is below. 我的代码如下。

triangleNumbers = [t | a <- [0..], let t = a*(a+1)/2] 
divisors triangleNumbers = [d | d <- [1..triangleNumbers], triangleNumbers 
`mod` d == 0]
numDivisors = takeWhile(<501) length . divisors
answer = divisors !! numDivisors

First of all, your triangleNumbers is a bit weird: it contains Fractional s, instead of Integrals s. 首先,您的triangleNumbers有点奇怪:它包含Fractional ,而不是Integrals This makes it more troublesome to perform accurate division calculations. 这使得执行精确的除法运算更加麻烦。 So we better modify this: 所以我们最好修改一下:

triangleNumbers = [ div (a*(a+1)) 2 | a <- [0..]]

Note that we can write the expression in the head of the list comprehension. 请注意,我们可以将表达式写在列表理解的开头。 We also use div over / since div is an integer division. 由于div是整数除法,因此我们也使用div over / We know for sure that we will not lose data by performing an integer division, since either a or a+1 is even, and the multiplication of a number with an even number is always even. 我们肯定知道我们不会因执行整数除法而丢失数据,因为aa+1是偶数,并且数字与偶数的乘积始终是偶数。 This results in the following list: 这将导致以下列表:

Prelude> take 10 triangleNumbers 
[0,1,3,6,10,15,21,28,36,45]

Now we want a function that maps numbers on the divisors. 现在我们需要一个将数字映射到除数上的函数。 We can make a generic function: 我们可以创建一个通用函数:

divisors x = [d | d <- [1..x], mod x d == 0]

Now we can use map , to map a list of numbers to a list of lists where each list contains the divisors of the original number. 现在我们可以使用map ,将一个数字列表映射到一个列表列表,其中每个列表都包含原始数字的除数。 So: 所以:

Prelude> map divisors [1,2,3,5,8,13,21]
[[1],[1,2],[1,3],[1,5],[1,2,4,8],[1,13],[1,3,7,21]]

We can however also give the map divisors the (infinite list) of triangleNumbers . 但是,我们也可以给map divisors提供triangleNumbers的(无限列表)。 For instance for the first 10 triangleNumbers : 例如前10个triangleNumbers

Prelude> take 10 $ map divisors $ triangleNumbers 
[[],[1],[1,3],[1,2,3,6],[1,2,5,10],[1,3,5,15],[1,3,7,21],[1,2,4,7,14,28],[1,2,3,4,6,9,12,18,36],[1,3,5,9,15,45]]

Now we only need to filter the numbers that have 501 elements or more. 现在,我们只需要过滤具有501个或更多元素的数字。 We can do this by checking that if we drop 500 elements, we still have a list that contains at least one element. 为此,我们可以检查是否drop 500元素,但仍然有一个至少包含一个元素的列表。 So with: 因此:

hasAtLeastLength :: Int -> [a] -> Bool
hasAtLeastLength n = not . null . drop (n-1)

So now we can filter all the elements where the hasAtLeastLengh 501 (divisors x) for a number x . 因此,现在我们可以将hasAtLeastLengh 501 (divisors x) filter为数字x所有元素。 This will thus produce the list of all these numbers: 因此,这将产生所有这些数字的列表:

filter (hasAtLeastLength 501 . divisors) triangleNumbers

This will produce an infinite list of all triangleNumbers that have at least 501 divisors. 这将产生一个所有具有至少501个除数的triangleNumbers的无限列表。 We can use head to finally obtain the first element: 我们可以使用head最终获得第一个元素:

head $ filter (hasAtLeastLengh 501 . divisors) triangleNumbers

This takes a large amount of time. 这需要大量时间。 The code works however quite fast if we work with 10 divisors: 如果我们使用10个除数,则代码的运行速度非常快:

Prelude> filter (hasAtLeastLength 10 . divisors) triangleNumbers
[120,210,276,300,378,496,528,630,666,780,820,990,1035,1128,1176,1275,1326,1485,1540,1596,1770,1830,1953,2016,2080,2145,2346,2415,2556,2628,2775,2850,2926,3003,3160,3240,3321,3486,3570,3828,3916,4005,4095,4186,4278,4560,4656,4851,4950,5050,5356,5460,5565,5778,5886,6105,6216,6328,6555,6670,6786,6903,7140,7260,7626,7750,7875,8001,8128,8256,8385,8646,8778,9045,9180,9316,9730,9870,10296,10440,10731,10878,11175,11325,11476,11628,11781,11935,12090,12246,12720,12880,13041,13203,13530,13695,14028,14196,14365,14535,14706,15225,15400,15576,16110,16290,16653,16836,17020,17205,17391,17578,17766,17955,18336,18528,18915,19110,19306,19503,19701,19900,20100,20706,20910,21321,21528,21736,21945,22155,22578,23220,23436,24090,24310,24531,24976,25200,25425,25878,26106,26565,26796,27028,27261,27495,27730,27966,28203,28680,28920,29403,29646,29890,30135,30381,30628,30876,31125,31626,31878,32385,32640,32896,33411,33670,33930,34191,34716,34980,35245,35511,35778,36315,36585,36856,37128,37401,37675,37950,38226,38781,39060,39340,40470,40755,41041,41328,41616,41905,42195,42486,43071,43365,43660,43956,44253,44850,45150,46056,46360,46665,46971,47278,47586,47895,48516,48828,49455,49770,50721,51040,51360,51681,52003,52326,52650,...

which means that it produces an answer. 这意味着它会产生答案。 This means however that you will have to come up with something smarter than simply enumerating. 但是,这意味着您将不得不想出比简单枚举更智能的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM