繁体   English   中英

在haskell中将整数列表转换为一个Int(如concat)

[英]Convert list of Integers into one Int (like concat) in haskell

标题说的差不多。 我有一个像这样的整数列表:[1,2,3]。 我想将其更改为 Integer 123。我的第一个想法是 concat 但这不起作用,因为它的类型错误,我尝试了各种方法,但通常我最终会返回相同的列表。 非常感谢任何帮助。

found a way to print the right thing (putStr) except I want the type to be Integer and putStr doesn't do that.此外,我找到了一种打印正确内容 (putStr) 的方法,但我希望类型为 Integer 而 putStr 不这样做。

您可以使用foldl来组合列表的所有元素:

fromDigits = foldl addDigit 0
   where addDigit num d = 10*num + d

addDigit函数由foldl调用以从最左边的数字开始一个接一个地添加数字。

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

编辑:
foldl从左到右遍历列表,添加元素以累积一些值。

foldl的第二个参数,在本例中为0 ,是进程的起始值。 在第一步骤中,该初始值与组合1 ,该列表的第一元件,通过调用addDigit 0 1 这导致 10*0+1 = 1。在下一步中,这个 1 与列表的第二个元素组合,通过addDigit 1 2 ,给出 10*1+2 = 12。然后这与列表的第三个元素组合列表,通过addDigit 12 3 ,导致 10*12+3 = 123。

所以无意义地乘以零只是第一步,在接下来的步骤中,实际上需要乘法来将新数字添加到累积数字的“末尾”。

您可以concat数字的字符串表示,然后read它们read回,如下所示:

joiner :: [Integer] -> Integer
joiner = read . concatMap show

这对我来说效果很好。

read (concat (map show (x:xs))) :: Int

函数如何读取:
第 1 步 - 将列表中的每个 int 转换为字符串(map show (x:xs))
第 2 步 - 将每个字符串组合在一起(concat (step 1))
第 3 步 - 将字符串读取为 int read (step 2) :: Int的类型read (step 2) :: Int

使用readintToDigit

joinInt :: [Int] -> Int
joinInt l = read $ map intToDigit l

具有在多位数字上呕吐的优势(或劣势)。

另一个想法是:最后一位数为 1,倒数第二位为 10,前一位数为 100,依此类推。 因此,要将数字列表转换为数字,您需要将其反转(以便从后面开始),将数字与相应的 10 的幂相乘,然后将结果相加。

要反转列表,请使用reverse ,要获得十的幂,您可以使用iterate (*10) 1 (在 GHCi 或 Hugs 中尝试!),将两个列表的相应数字相乘使用zipWith (*)并将所有内容加在一起,使用sum - 了解一些库函数真的很有帮助! 把这些位放在一起,你得到

fromDigits xs = sum (zipWith (*) (reverse xs) (iterate (*10) 1))

评估示例:

fromDigits [1,2,3,4]  
    ==> sum (zipWith (*) (reverse [1,2,3,4]) [1,10,100,1000, ....]
    ==> sum (zipWith (*) [4,3,2,1] [1,10,100,1000, ....])
    ==> sum [4 * 1, 3 * 10, 2 * 100, 1 * 1000]
    ==> 4 + 30 + 200 + 1000
    ==> 1234

但是,此解决方案比foldl解决方案慢,这是由于调用了reverse并且您正在构建 10 的幂,只是为了再次直接使用它们。 从好的方面来说,这种构建数字的方式更接近人们通常的思考方式(至少我是这样!),而foldl -solutions 本质上使用了Horner 的规则

至于如何打印数字,而不是

putStr n

试试吧

putStr (show n)

原因是putStr只能打印字符串。 所以你需要在传入之前将数字转换为字符串。

您可能还想尝试 Prelude 的print功能。 这个可以打印任何“可显示”的东西(类Show任何实例),而不仅仅是字符串。 但请注意, print n对应于(大致) putStrLn (show n) ,而不是putStr (show n)

join :: Integral a => [a] -> a
join [x] = x
join (x:xs) = (x * (10 ^ long)) + join(xs)
    where long = length(x:xs)

我们可以定义名为join的函数,该函数给定一个整数列表,它可以返回另一个整数。 我们使用递归将给定列表的头部与列表的其余部分分开,我们使用模式匹配来定义边缘条件,以便递归可以结束。

我不是 Haskell 的专家,但这是我能想到的解决此问题的最简单方法,不涉及使用任何其他外部函数。

concatDigits :: [Int] -> Int
concatDigits [] = 0
concatDigits xs = concatReversed (reverseDigits xs) 1

reverseDigits :: [Int] -> [Int]
reverseDigits [] = []
reverseDigits (x:xs) = (reverseDigits xs) ++ [x]

concatReversed :: [Int] -> Int -> Int
concatReversed [] d = 0
concatReversed (x:xs) d = (x*d) + concatReversed xs (d*10)

如您所见,我假设您正在尝试连接数字列表。 如果这不是你的情况,我很确定这不会奏效。 :(

在我的解决方案中,首先我定义了一个名为reverseDigits的函数,它反转原始列表。 例如 [1,2,3] 到 [3,2,1]

之后,我使用了一个concatReversed函数,它接受一个数字列表和数字 d,这是列表位置第一个数字的十次幂的结果。 如果列表为空,则返回 0,如果不是,则返回列表中的第一个数字乘以 d,加上对concatReversed的调用传递列表的其余部分和 d 乘以 10。

希望代码不言自明,因为我认为我糟糕的英语解释不是很有帮助。


编辑

很长一段时间后,我发现我的解决方案非常混乱,因为它需要反转列表,以便能够从右到左将每个数字乘以列表中数字索引的 10 次方。 现在知道元组,我看到更好的方法是有一个函数来接收累积的转换部分和列表的其余部分,因此在每次调用中将累积部分乘以 10,然后添加当前数字。

concatDigits :: [Int] -> Int
concatDigits xs = aggregate (xs, 0)
  where aggregate :: ([Int], Int) -> Int
        aggregate ([], acc) = acc
        aggregate (x:xs, acc) = aggregate (xs, (acc * 10 + x))

暂无
暂无

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

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