簡體   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