关于循环:Haskell-“迭代并填充”列表

Haskell - Iterate and Populate list

我对Haskell还是很陌生,这是迄今为止我发现的最难缠的语言。我在网上找到了一篇过往的论文,因此决定尝试在haskell中进行实践。

我的myFile.txt中有一个整数列表,如下所示:

1
2
3
4
5
6
5
3 30
10 120
80 96
95 96
98 98

列表中第一个数字的整数是告诉我接下来要进行的测试次数。在这种情况下,将跟随5。

我正在尝试为每个测试(例如3 30)返回一个数字(例如:20),以表示特定范围内的总倍数。

第一个测试的示例为3 30:

  • 我需要找到从2到第一个数字(在这种情况下为2和3)的每个数字的倍数,最大为30。在这种情况下:

    2的倍数:[2,4,6,8,10,12,14,16,18,20,22,24,26,28,30]

    3的倍数:[3,6,9,12,15,18,21,24,27,30]

  • 然后我找到相似的东西,然后计算所有唯一值:

    [2,3,4,6,8,9,10,12,14,15,16,18,20,21,22,24,26,27,28,30]

  • 第2个最终列表的大小为20,这就是我要返回的值。

    话虽如此,我对如何执行此实现有想法。我执行此实现的计划是:

  • 用数字的倍数填充单个列表
    小于并等于收到的第一个数字。
  • 将填充的列表进行分组。
  • 取组的长度,然后
    打印值。
  • 首先,我已完成以下操作以读取所有输入,将其存储到列表中并将其传递给函数以进行打印,以确认我已收到正确的值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    main = do  
        let myList = []
        handle <- openFile"myFile.txt" ReadMode
        contents <- hGetContents handle
        let singlewords = words contents
            myList = f singlewords
        printMyVals myList
        hClose handle

    f :: [String] -> [Integer]
    f = map read


    printMyVals :: [Integer] -> IO()
    printMyVals myList =
        print myList

    这时,我被卡住了。

    我试图弄清楚如何迭代列表的值,并使用这些值以其倍数填充另一个列表,如上文所述。

    对此有任何帮助吗?


    所以这有几个部分,如果将??它们分解成每一步,那么每个步骤都非常简单。每行的输入为mn

  • 查找2和n之间的所有2的倍数。
  • 查找mn之间的m的所有倍数
  • 将两个列表排序在一起,删除重复项
  • 获取结果列表的长度并打印
  • 第1步和第2步在同一函数中处理:

    1
    multiplesOfN n = [n, n+n..]

    这将建立一个无数的倍数值列表。应用takeWhile (<=x)获取上限值。对于输入的第一行,您将具有:

    1
    2
    twos   = takeWhile (<=30) . multiplesOfN $ 2
    threes = takeWhile (<=30) . multiplesOfN $ 3

    这时,您需要将两个列表合并在一起,删除重复项。由于它们都是升序列表,因此只需一步合并排序即可轻松实现。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    mergesort :: (Eq a, Ord a) => [a] -> [a] -> [a]
    mergesort [] ys = ys
    mergesort xs [] = xs
    mergesort xss@(x:xs) yss@(y:ys)
      | x < y     = x : mergesort xs yss
      | otherwise = y : mergesort xss ys
    -- but this doesn't remove duplicates! Let's deal with that by
    -- adding a new argument @lastValue@ and discarding if any match

    uniqMergesort :: (Eq a, Ord a) => [a] -> [a] -> [a]
    uniqMergesort xs [] = xs
    uniqMergesort [] ys = ys
    uniqMergesort xss@(x:xs) yss@(y:ys)
      | x < y     = x : go x xs  yss
      | otherwise = y : go y xss ys
      where
      go _ [] [] = []
      go lastValue (x:xs) []
        | lastValue == x =     go lastValue xs []
        | otherwise      = x : go lastValue xs []
      go lastValue [] (y:ys)
        | lastValue == y =     go lastValue [] ys
        | otherwise      = y : go lastValue [] ys
      go lastValue xss@(x:xs) yss@(y:ys)
        | x < y     = if   x == lastValue
                      then     go lastValue xs yss
                      else x : go x         xs yss
        | otherwise = if   y == lastValue
                      then     go lastValue xss ys
                      else y : go y         xss ys

    获得结果列表的长度仅为length,并且从文件中提取值分为几行,然后是单词,然后读取每个单词。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    main :: IO ()
    main = do
      handle <- openFile"myFile.txt" ReadMode
      contents <- hGetContents handle
      let inputs  = map (map read . words) . lines $ tail contents
          results = [let xs = takeWhile (<=n) . multiplesOfN $ 2
                         ys = takeWhile (<=n) . multiplesOfN $ m
                     in  uniqMergesort xs ys | [m, n] <- inputs]
      mapM_ (print . length) results
      hClose handle