【问题标题】:Haskell List of Int : [123] to [1,2,3]Haskell 整数列表:[123] 到 [1,2,3]
【发布时间】:2011-06-10 10:18:28
【问题描述】:

问题

我的 int 列表为 [123,123],我需要为 [1,2,3,1,2,3]

当前代码

我使用递归尝试了以下代码

fat::[Int]->[Int]
fat [] = []
fat (a,b,c:xs) = a : b : c : fat xs

结论

我不知道如何在列表 [123,123] 中将值分别访问为 '1' 、 '2 、 '3

【问题讨论】:

  • 要将数字拆分为数字,请参阅stackoverflow.com/questions/3963269/…
  • 为了什么?听起来这个问题受到了臭名昭著的XY problem的影响。
  • 我不知道为什么有人不赞成这个!?如果您这样做,请发表评论。

标签: list haskell


【解决方案1】:

我建议对列表的每个元素使用this answer 中给出的digs 函数。它将Int 拆分为一个数字列表([Int])。然后你只需要连接结果列表。这个“映射和连接结果”要求对于concatMap 来说是一项完美的工作

fat :: [Int] -> [Int]
fat = concatMap digs

这给出了:

*Main> fat [123,123]
[1,2,3,1,2,3]

如果我理解正确的话,这就是你想要的。

【讨论】:

    【解决方案2】:
    splitNum :: Int -> [Int]
    splitNum n | n <= 9     = [n]
               | otherwise  = (splitNum (n `div` 10)) ++ [n `mod` 10]
    
    fat :: [Int] -> [Int]
    fat x = concatMap splitNum x
    

    splitNum 用于将 Int 转换为 [Int],方法是将其拆分为十个提醒的除法,并将生成的 Int 附加到拆分后的其余部分(递归!)

    现在,拥有一个将数字转换为列表的函数,通过输入,将 splitNum 应用于内部列表中的任何数字并连接所有结果列表(列表理解!)

    【讨论】:

    • 当心:[01010] 得到 [1,0,1,0]。
    • 好的,不赞成。仍然希望少一点“这里的代码”和多一点指导手。
    • 当然是:cse.chalmers.se/~hallgren/CactusExample/Haskell.bnf!稍微减少一点后,你会得到 "integer = ['0'..'9']+ | "0"["oO"]Octal | "0"["xX"]Hexadecimal" 对我们来说,第一种情况整数很有趣。 010101 适合“['0'..'9']+”,因此它是一个整数
    【解决方案3】:

    作为一个新的 Haskell 程序员,我会告诉你我对这个问题的看法。只是因为我认为有很多选择很好,尤其是来自不同经验的不同人。

    这是我对这个问题的看法:

    • 对于列表中的每个项目,使用 read 将该项目转换为 char 列表。
    • 将该 char 列表发送到一个函数,该函数将该列表中的每个项目转换为一个 int,然后返回一个 int 列表。
    • 将该整数列表连接到主列表中。

    澄清一下:

    • [123, 234]
    • 123变成['1', '2', '3']
    • ['1', '2', '3'] 变成 [1, 2, 3]
    • [1, 2, 3] 在主列表中获得连接
    • 循环重复 234 次。

    util 函数看起来像这样:

    import Char
    
    charsToInts :: [Char] -> [Int]
    charsToInts [] = []
    charsToInts (x:xs) = digitToInt x : charsToInts xs
    

    来自一个迫切的背景,这就是我解决它的方式。可能比仅在数学上拆分数字要慢,但我认为展示一个替代方案会很有趣。

    【讨论】:

    • 这真的很复杂很复杂,因为 read :: Read a => String -> a.
    • 介意解释原因或给我看一些关于它的内容吗? :) 非常适合了解更多信息。
    • 我认为这不适合 cmets 部分,因为没有格式。编辑:这并不意味着我不想帮助你。但是告诉我怎么做!
    • 是的,没错。也许我应该阅读类型系统并尝试更好地理解它以理解为什么这会很复杂?还是您建议我阅读其他内容?
    • ISBN 9780521692694:一本非常好的 Haskell 课程书,适合自学。关于 Haskell 的书籍非常少见,但如果您使用“传统”语言,并且有更流行的函数式语言(如 Scheme),Haskell 很难学习,因此只有书呆​​子(或知道自己在做什么的人)才会写它。
    【解决方案4】:

    为了直截了当地查明问题,您不知道如何单独访问数字,因为您不了解 Haskell 类型和模式匹配。让我尝试帮助消除您的一些误解。

    让我们看看你的清单:

    [123, 123]
    

    它的类型是什么?这显然是一个整数列表,或[Int]。使用列表,您可以在构造函数:模式匹配,lispers 将其称为“cons”或“列表构造函数”。您在: 的左侧放置了一个元素,在右侧放置了另一个列表。右边的列表可以是空列表[],基本表示列表结束。 Haskell 提供了“语法糖”以使列表更易于编写,但 [123,456] 实际上被脱糖为 123:(456:[])。因此,当您对(x:y:z) 进行模式匹配时,您现在可以看到x 将被分配123y 将被分配456z 将是xy 之后的列表的其余部分;在这种情况下,只剩下[]

    那么,与: 匹配的模式适用于列表Ints 不是列表,因此您不能使用 :Int 的数字进行模式匹配。但是,Strings 列表,因为String[Char] 相同。因此,如果您将 Int 转换为 String,那么您可以在每个字符上进行模式匹配。

    map show [123, 123]
    

    map 将函数应用于列表的所有元素。 show 可以将Int 转换为String。所以我们在Ints 的列表上map show 得到Strings 的列表。

    ["123", "123"]
    

    现在让我们将这些Strings 转换为Ints 的列表。由于String 只是[Char],我们将再次使用map

    map digitToInt "123" -- this requires that you import Data.Char (digitToInt)
    

    这会给我们[1,2,3];列表中的每个Char 都会变成Int。这就是我们想要对列表["123", "123"] 中的每个String 执行的操作。我们想map digitToInt 到每个字符串。但是我们有一个Strings 的列表。那么我们该怎么办?我们映射它!

    map (map digitToInt) ["123", "123"]
    

    这会给我们[[1,2,3], [1,2,3]]。几乎是我们想要的。现在我们只需要将Ints ([[Int]]) 的列表扁平化为Int ([Int]) 的列表。我们怎么能做到这一点?停止......胡歌时间! Hoogling [[a]] -> [a] 我们发现第一个命中 concat 正是我们想要的。

    让我们把它们放在一起。首先我们使用map show 来从[Int][String]。然后我们执行map (map digitToInt) 以从[String][[Int]]。然后我们执行concat 以从[[Int]][Int]。那我们就直接print吧!

    import Data.Char (digitToInt)
    main = print $ concat $ map (map digitToInt) $ map show $ [123, 123]
    

    现在让我们将大部分内容提取到函数 fat

    import Data.Char (digitToInt)
    main = print $ fat [123, 123]
    fat :: [Int] -> [Int]
    fat xs = concat $ map (map digitToInt) $ map show $ xs
    

    从这里您可以通过几种不同的方式使其更漂亮。 concat $ mapconcatMap 相同,由于我们按顺序映射(map digitToInt)show,我们可以合并它们。同样让它变得无意义,我们可以得到一个相当简洁的定义:

    fat = concatMap (map digitToInt . show)
    

    【讨论】:

      【解决方案5】:

      为了完整起见,我按照@Ancide的建议写了它

      实施

      fat' :: [Int] -> [Int]
      fat' l = map (read) [[z] | z <- [x | k <- (map (show) l), x <- k]]         
      

      解释

      {- last result -} 代表最后解释的代码的结果。

      map (show) l
      

      这会获取 l 中的每个元素并将其转换为 [String]

      [x | k <- {- last result -}, x <- k]
      

      k 遍历 last result 中的所有元素时,x 枚举每个 k 中的所有字符。所有这些都添加到列表中。现在你有一个 String,分别是一个 [Char],所有数字都彼此相邻。

      [[z] | z <- {- last result -}]
      

      这部分从 String 中取出每个 Char 并将其放入一个空的 String 中。注意 [z] 部分!这会在 z 周围创建一个列表,它(见上文)与 String 相同。现在你有一个 String 列表,每个数字都有一个 String

      map (read) {- last result -}
      

      这会获取最后一个结果中的每个项目并将其转换回Int并将它们连接到[Int]。现在您有了想要结果的 [Int] 类型列表。

      简历

      虽然这种实现是可能的,但由于所有类型转换,它既不快,也不可读。

      【讨论】:

      • 注意:这不是 Haskell 编译器实际解析的方式。但是将惰性评估纳入其中是很难理解的。
      【解决方案6】:

      玩弄列表单子我想出了这个。几乎相同的@Ankur 的解决方案,除了使用列表单子:

      fat :: [Int] -> [Int]
      fat is = is >>= show >>= return . digitToInt
      

      【讨论】:

        【解决方案7】:

        如果您有两个数字,ab,那么您可以通过 10*a + b 将它们变成一个数字。相同的原则适用于三个。

        听起来这样做的一种方法是将splitEvery 分成三个一组,然后map 一个函数将三个组成的列表变成一个数字。

        这有帮助吗?

        【讨论】:

          【解决方案8】:

          你需要一个函数来将 Integer 转换为 string... 这显然是 Show 函数 另一个将 Char 转换为 Integer 的函数,即模块 Char 中的“digitToInt”

          我们开始吧:

          fat::[Int]->[Int]
          fat [] = []
          fat ls = concat $ map (map digitToInt) (map show ls)
          

          如果它有效,请告诉我:)

          【讨论】:

            猜你喜欢
            • 2015-04-21
            • 1970-01-01
            • 2017-09-11
            • 1970-01-01
            • 2012-08-30
            • 2012-04-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多