Haskell 将 Int 转换为 alpha numerotation 的函数
Haskell function to convert Int to alpha numerotation
我正在尝试编写一个 Haskell 函数来将整数转换为带有字母数字旋转的字符串。
通过 alpha numerotation,我的意思是与此转换匹配的 numerotation:
1 -> A
2 -> B
3 -> C
..
25 -> Y
26 -> Z
27 -> AA
28 -> AB
29 -> AC
..
我发现这个 function 可以将十进制数转换为罗马数,并尝试对其进行修改以实现我想要的效果。但是我没有设法得到正确的结果。问题是,在 alpha numerotation 中,"A" 用作单位或倍数时 "weight" 不同(它可能值 1 或 0)。
你知道如何获得正确的转换吗?
我们这里可以先把这个数转化为一个数列,每次除以26,然后求模:
import Data.List(unfoldr)
toColumnName :: Int -> String
toColumnName = reverse . fmap (toEnum . (64+)) . unfoldr f
where f 0 = Nothing
f n = Just ((mod (n-1) 26)+1, div (n-1) 26)
或更短:
import Data.List(unfoldr)
import Data.Tuple(swap)
toColumnName :: Int -> String
toColumnName = reverse . fmap (toEnum . (65+)) . unfoldr f
where f 0 = Nothing
f n = Just (swap (divMod (n-1) 26))
例如:
Prelude Data.List> map toColumnName [1..100]
["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK","AL","AM","AN","AO","AP","AQ","AR","AS","AT","AU","AV","AW","AX","AY","AZ","BA","BB","BC","BD","BE","BF","BG","BH","BI","BJ","BK","BL","BM","BN","BO","BP","BQ","BR","BS","BT","BU","BV","BW","BX","BY","BZ","CA","CB","CC","CD","CE","CF","CG","CH","CI","CJ","CK","CL","CM","CN","CO","CP","CQ","CR","CS","CT","CU","CV"]
模运算非常简单。我们将编写一个 returns 字母倒序的函数;之后我们可以在顶层修复它。基本思路就是重复除以26。所以:
rawCellName :: Int -> String
rawCellName x | x <= 0 = []
rawCellName x = toEnum (fromEnum 'A' + r) : rawCellName q where
(q, r) = (x-1) `quotRem` 26
然后在顶层我们只修复 API 奇怪的地方:
cellName :: Int -> String
cellName = reverse . rawCellName
在 ghci 中试试看:
> map cellName [1..5]
["A","B","C","D","E"]
> map cellName [25..30]
["Y","Z","AA","AB","AC","AD"]
我正在尝试编写一个 Haskell 函数来将整数转换为带有字母数字旋转的字符串。
通过 alpha numerotation,我的意思是与此转换匹配的 numerotation:
1 -> A
2 -> B
3 -> C
..
25 -> Y
26 -> Z
27 -> AA
28 -> AB
29 -> AC
..
我发现这个 function 可以将十进制数转换为罗马数,并尝试对其进行修改以实现我想要的效果。但是我没有设法得到正确的结果。问题是,在 alpha numerotation 中,"A" 用作单位或倍数时 "weight" 不同(它可能值 1 或 0)。
你知道如何获得正确的转换吗?
我们这里可以先把这个数转化为一个数列,每次除以26,然后求模:
import Data.List(unfoldr)
toColumnName :: Int -> String
toColumnName = reverse . fmap (toEnum . (64+)) . unfoldr f
where f 0 = Nothing
f n = Just ((mod (n-1) 26)+1, div (n-1) 26)
或更短:
import Data.List(unfoldr)
import Data.Tuple(swap)
toColumnName :: Int -> String
toColumnName = reverse . fmap (toEnum . (65+)) . unfoldr f
where f 0 = Nothing
f n = Just (swap (divMod (n-1) 26))
例如:
Prelude Data.List> map toColumnName [1..100]
["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","AA","AB","AC","AD","AE","AF","AG","AH","AI","AJ","AK","AL","AM","AN","AO","AP","AQ","AR","AS","AT","AU","AV","AW","AX","AY","AZ","BA","BB","BC","BD","BE","BF","BG","BH","BI","BJ","BK","BL","BM","BN","BO","BP","BQ","BR","BS","BT","BU","BV","BW","BX","BY","BZ","CA","CB","CC","CD","CE","CF","CG","CH","CI","CJ","CK","CL","CM","CN","CO","CP","CQ","CR","CS","CT","CU","CV"]
模运算非常简单。我们将编写一个 returns 字母倒序的函数;之后我们可以在顶层修复它。基本思路就是重复除以26。所以:
rawCellName :: Int -> String
rawCellName x | x <= 0 = []
rawCellName x = toEnum (fromEnum 'A' + r) : rawCellName q where
(q, r) = (x-1) `quotRem` 26
然后在顶层我们只修复 API 奇怪的地方:
cellName :: Int -> String
cellName = reverse . rawCellName
在 ghci 中试试看:
> map cellName [1..5]
["A","B","C","D","E"]
> map cellName [25..30]
["Y","Z","AA","AB","AC","AD"]