2016-05-11 6 views
1

次のコードがあります。これは、Excelの列タイプに対応する数値を変換する必要があります。たとえば、28に27とABにAA:折りたたみ内のタプルに一致しません

import Data.Char (ord) 
import Data.List (foldl1') 

columnToNumber :: String -> Int 
columnToNumber s = foldl1' (\acc (i, v) -> acc + 26^i * v) (values s) 
    where values s = zip (reverse [0..(length s)]) ((\c -> ord c - 64) <$> s) 

アイデアは、対応する番号

["A", "A"] -> [1, 1] 

と右からそうベースでそれをジップに変換文字列「AA」を取ることです左に26^0,26^1,26^2などがあります。

zip [1, 0] [1, 1] -> [(1, 1), (0, 1)] 

倍の結果は残念ながら、私は次のエラーを

26^1 * 1 + 26^0 * 1 = 27 

を得ていることだろうと私はなぜわからないその方法:

ExcelSheetColumn.hs:7:34: 
    Couldn't match expected type ‘Int’ 
       with actual type ‘(Integer, Int)’ 
    In the pattern: (i, v) 
    In the first argument of ‘foldl1'’, namely 
     ‘(\ acc (i, v) -> acc + 26^i * v)’ 
    In the expression: 
     foldl1' (\ acc (i, v) -> acc + 26^i * v) (values s) 

ExcelSheetColumn.hs:7:63: 
    Couldn't match type ‘(Int, Int)’ with ‘Int’ 
    Expected type: [Int] 
     Actual type: [(Int, Int)] 
    In the second argument of ‘foldl1'’, namely ‘(values s)’ 
    In the expression: 
     foldl1' (\ acc (i, v) -> acc + 26^i * v) (values s) 

誰かが助けてもらえ私は出る?

+1

まあ最初私はあなたが '長さSを使用したいと思います。 –

答えて

6

それはあなたが実際にちょうどfoldl'foldl1'を切り替えてアキュムレータを開始を追加する必要がコンパイル取得するには:

import Data.Char (ord) 
import Data.List (foldl') 

columnToNumber :: String -> Int 
columnToNumber s = foldl' (\acc (i, v) -> acc + 26^i * v) 0 (values s) 
    where values s = zip (reverse [0..(length s)]) ((\c -> ord c - 64) <$> s) 

あなたが作った提案Free_Dlength s - 1から開始)を追加する場合:

columnToNumber :: String -> Int 
columnToNumber s = foldl' (\acc (i, v) -> acc + 26^i * v) 0 (values s) 
    where values s = zip (reverse [0..(length s -1)]) ((\c -> ord c - 64) <$> s) 

希望の結果が得られます。

λ> columnToNumber "AA" 
27 
λ> columnToNumber "AB" 
28 

これを必要とするが、ちょっと、なぜあなたが実際つもりならば、私は知りません:あなたはおそらく好きではない何

columnToNumber "A1"11であるということです - あなたは違ったから数字踏む必要があり、この問題を解決するために手紙:

columnToNumber :: String -> Int 
columnToNumber s = foldl' (\acc (i, v) -> acc + 26^i * v) 0 (values s) 
    where values s = zip (reverse [0..(length s -1)]) (parse <$> s) 
     parse c 
      | c >= '0' && c <= '9' = ord c - ord '0' 
      | otherwise = ord c - 64 
+0

Ah foldl1 - > foldlはとても簡単でした。 – m0meni

2

foldl1'の定義を見てみると、それは似たような同じタイプである二つのものを取り、生産するために持ってい

*Main Data.List> :t foldl1' 
foldl1' :: (a -> a -> a) -> [a] -> a 

しかしfoldlが何をしたいです:

*Main Data.List> :t foldl 
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b 

だから、基本的に、この: - 1 '自分の価値観の機能に

import Data.Char (ord, toUpper) 

columnToNumber :: String -> Int 
columnToNumber s = foldl (\acc (i, v) -> acc + 26^i * v) 0 $ values s where 
    values s = zip [l - 1, l - 2 ..0] ((\c -> (ord.toUpper) c - 64) <$> s) where 
     l = length s 
+0

'[l - 1、l - 2 ..0]'あなたがこれを行うことができないと思いませんでした! – m0meni

関連する問題