[英]Haskell List of Int : [123] to [1,2,3]
问题
我的 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”
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 附加到拆分后的 rest(递归!)
现在,有一个 function 将数字转换为列表,go 通过输入,将 splitNum 应用于内部列表中的任何数字并连接所有结果列表(列表理解!)
作为一个新的 Haskell 程序员,我会给你我对这个问题的想法。 只是因为我认为有很多选择很好,尤其是来自不同经验的不同人。
这是我对这个问题的看法:
澄清:
util function 看起来像这样:
import Char
charsToInts :: [Char] -> [Int]
charsToInts [] = []
charsToInts (x:xs) = digitToInt x : charsToInts xs
来自势在必行的背景,这就是我解决它的方式。 可能比仅在数学上拆分数字要慢,但我认为展示一个替代方案会很有趣。
直截了当地指出问题,您不知道如何单独访问数字,因为您不了解 Haskell 类型和模式匹配。 让我试着帮助消除你的一些误解。
让我们看看你的清单:
[123, 123]
它的类型是什么? 它显然是一个整数列表,或[Int]
。 使用列表,您可以在构造函数:
上进行模式匹配,lispers 将其称为“cons”或“列表构造函数”。 您在:
的左侧放置了一个元素,在右侧放置了另一个列表。 右边的列表可以是空列表[]
,基本表示列表的结束。 Haskell 提供了“语法糖”以使列表更易于编写,但[123,456]
实际上被脱糖为123:(456:[])
。 因此,当您进行模式匹配(x:y:z)
时,您现在可以看到x
将被分配123
并且y
将被分配456
。 z
将是x
和y
之后列表的 rest ; 在这种情况下,只剩下[]
。
现在,与:
的模式匹配适用于列表。 Int
不是列表,因此您不能使用:
对Int
的数字进行模式匹配。 但是, String
是列表,因为String
与[Char]
相同。 因此,如果您将Int
转换为String
,则可以对每个字符进行模式匹配。
map show [123, 123]
map
将 function 应用于列表的所有元素。 show
可以采用Int
并将其转换为String
。 所以我们map show
Int
的列表以获得String
的列表。
["123", "123"]
现在让我们将这些Strings
转换为Int
的列表。 由于String
只是[Char]
,我们将再次使用map
。
map digitToInt "123" -- this requires that you import Data.Char (digitToInt)
这会给我们[1,2,3]
; 列表中的每个Char
都变成一个Int
。 这就是我们想要对列表["123", "123"]
中的每个String
执行的操作。 我们希望map digitToInt
到每个字符串。 但是我们有一个String
的列表。 那么我们该怎么办? 我们map吧!
map (map digitToInt) ["123", "123"]
这会给我们[[1,2,3], [1,2,3]]
。 几乎是我们想要的。 现在我们只需要将Int
列表 ( [[Int]]
) 列表展平为Int
列表 ( [Int]
)。 我们怎么能做到这一点? 停止......胡歌时间! 搜索[[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]
现在让我们将大部分内容提取到 function fat
中
import Data.Char (digitToInt)
main = print $ fat [123, 123]
fat :: [Int] -> [Int]
fat xs = concat $ map (map digitToInt) $ map show $ xs
从这里你可以用几种不同的方式让它更漂亮。 concat $ map
与concatMap
相同,并且由于我们 map 两者(map digitToInt)
并按顺序show
,我们可以合并它们。 同样让它变得无意义,我们可以得到一个非常简洁的定义:
fat = concatMap (map digitToInt . show)
为了完整起见,我按照@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遍历最后一个结果中的所有元素时, x枚举每个k中的所有字符。 所有这些都添加到列表中。 现在您有一个String ,分别是一个[Char] ,所有数字都彼此相邻。
[[z] | z <- {- last result -}]
这部分从String中获取每个Char并将其放入一个空String中。 注意[z]部分! 这会在z周围创建一个列表,这与String相同(见上文)。 现在你有一个字符串列表,每个数字都有一个字符串。
map (read) {- last result -}
这将获取最后一个结果中的每个项目并将其转换回Int并将它们连接到[Int] 。 现在您有了想要结果的[Int]类型列表。
恢复
尽管这种实现是可能的,但由于所有类型转换,它既不快,也不可读。
玩弄列表单子我想出了这个。 几乎相同的@Ankur 的解决方案,除了使用列表单子:
fat :: [Int] -> [Int]
fat is = is >>= show >>= return . digitToInt
如果你有两个数字, a
和b
,那么你可以通过 10*a + b 将它们变成一个数字。 同样的原则适用于三个。
听起来这样做的一种方法是将Every分成三个块,然后将map
a function 将三个列表变成一个数字。
这有帮助吗?
You need a function to convert Integer to string... which is obviously Show function Another function to convert a Char to Integer which is "digitToInt" in module Char
在这里我们 go:
fat::[Int]->[Int]
fat [] = []
fat ls = concat $ map (map digitToInt) (map show ls)
请让我知道它是否有效:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.