2016-12-03 62 views
1

在下面的代碼中,我很滿意功能,即代碼生成我期望的輸出。但是,比較至Col至Int的長度 - 我有興趣瞭解您是否可以提供某些內容(即至Col)。非常感謝!Excel列到Int,反之亦然 - 尋求改進

-- given a spreadsheet column as a string 
-- returns integer giving the position of the column 
-- ex: 
-- toInt "A" = 1 
-- toInt "XFD" = 16384 
toInt :: String -> Int 
toInt = foldl fn 0 
    where 
    fn = \a c -> 26*a + ((ord c)-64) 

-- given a integer returns 
-- the column to be found at that position as a [Char] 
-- ex: 
-- toCol 1 = "A" 
-- toCol 16384 = "XFD" 
toCol :: Int -> [Char] 
toCol n = toCol' n [] 
    where 
    toCol' 0 a = a 
    toCol' n a = 
     let r = mod n 26 in 
     case (r == 0) of 
      True -> toCol' (div (n-1) 26) ('Z':a) 
      False -> toCol' (div n 26) (chr(r + 64) : a) 
+0

建議無關你的問題:(1)你應該使用'foldl''(從'Data.List模塊')而不是'toInt'中的'foldl' - 參見[* foldr與foldl(或foldl')*]的影響(http://stackoverflow.com/q/384797/2751851)。 (2)你可能想考慮使用'toInt :: String - > Maybe Int',這樣如果給出一個無效的字符串(例如'「@#!」'),你就不會被迫返回無稽之談。 – duplode

回答

2

每當你遞歸建立一個有限的名單,認爲從Data.Listunfoldr :: (b -> Maybe (a, b)) -> b -> [a](儘管因爲它是從錯誤的方向展開,我們最終需要扭轉列表太)。語法擴展MultiWayIf也有助於使事情更好。

{-# LANGUAGE MultiWayIf #-} 

toCol :: Int -> [Char] 
toCol = reverse . unfoldr (\n -> let r = n `mod` 26 in 
      if | n == 0 -> Nothing 
      | r == 0 -> Just ('Z'   , n-1 `div` 26) 
      | otherwise -> Just (chr (r + 64), n `div` 26)) 

請注意,這也使得toCol點免費。如果你寧願沒有啓用的擴展,寧願模式匹配,你也可以這樣做:

toCol :: Int -> [Char] 
toCol = reverse . unfoldr (\n -> case (n, n `mod` 26) of 
            (0, _) -> Nothing 
            (n, 0) -> Just ('Z'   , n-1 `div` 26) 
            (n, r) -> Just (chr (r + 64), n `div` 26)) 
+0

我的自行車風格偏好將會傾向於'=='上的模式匹配,所以'case mod 26 of ... r - > ...'。 – jberryman