fugafuga.write

日々のログ



すごいH本 part33

今週のお題「2018年の抱負」

Data.Mapの話

連想リストを使うMapを使うということにする。Data.Mapはキーが順序付けされていることを利用して、効率よくキーを配置したりキーにアクセスしたりできる。

Data.MapPreludeData.Listと競合する名前をエクスポートしているので修飾付きインポートを行う。

import qualified Data.Map as Map

Data.Map.fromListを使って連想リストをMapに変換する

*Main> Map.fromList [(3,"shoes"),(4,"trees"),(9,"bees")]
fromList [(3,"shoes"),(4,"trees"),(9,"bees")]

元の連想リストに同じキーがあった場合は後のほうの要素が使われる。

連想リストをMapで実装する

phoneBook :: Map.Map String String
phoneBook = Map.fromList $
  [("betty", "555-2938")
  ,("bonnie1", "334-8878")
  ,("bonnie2", "334-8878")
  ,("bonnie3", "334-8878")
  ,("bonnie4", "334-8878")
  ]

実行結果

*Main> Map.lookup "betty" phoneBook
Just "555-2938"

phoneBookに新しい電話番号を挿入して新しいMapを作る

*Main> :t Map.insert
Map.insert :: Ord k => k -> a -> Map.Map k a -> Map.Map k a
*Main> Map.lookup "foo" phoneBook
Nothing
*Main> let newBook = Map.insert "foo" "123-5678" phoneBook
*Main> Map.lookup "foo" newBook
Just "123-5678"

電話番号がいくつあるか調べる

*Main> :t Map.size
Map.size :: Map.Map k a -> Int
*Main> Map.size phoneBook
5
*Main> Map.size newBook
6

電話番号を文字列でなく、Int のリストで表現したい。

string2digits :: String -> [Int]
string2digits = map digitToInt . filter isDigit

実行結果

*Main> string2digits "123-5678"
[1,2,3,5,6,7,8]

phoneBook に適用する

*Main> let intBook = Map.map string2digits phoneBook
*Main> :t intBook
intBook :: Map.Map String [Int]
*Main> Map.lookup "betty" intBook
Just [5,5,5,2,9,3,8]

1人が複数の電話番号を持っている場合に対応する。

phoneBook = Map.fromList $
  [("betty", "555-2938")
  ,("bonnie1", "334-8878")
  ,("bonnie1", "334-8877")
  ,("bonnie1", "334-8876")
  ,("bonnie1", "334-8875")
  ,("bonnie2", "334-8878")
  ,("bonnie3", "334-8878")
  ,("bonnie3", "335-8878")
  ,("bonnie4", "334-8878")
  ]

これだと、重複しているキーのペアは最後の要素が優先されてしまう。

*Main> phoneBook
fromList [("betty","555-2938"),("bonnie1","334-8875"),("bonnie2","334-8878"),("bonnie3","335-8878"),("bonnie4","334-8878")]

この問題を解決するにはData.Map.fromListWithを使う。この関数はキーの重複を削除しない。そのかわり、重複していた場合にどうするか決める関数を受け取る。

phoneBookToMap :: (Ord k) => [(k, String)] -> Map.Map k String
phoneBookToMap xs = Map.fromListWith add xs
  where add number1 number2 = number1 ++ ", " ++ number2

実行結果

*Main> Map.lookup "bonnie1" $ phoneBookToMap phoneBook
Just "334-8875, 334-8876, 334-8877, 334-8878"

所感

編集途中で投稿してしまってた。

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

  • 作者: MiranLipovaca
  • 出版社/メーカー: オーム社
  • 発売日: 2017/07/14
  • メディア: Kindle版
  • 購入: 4人 クリック: 9回
  • この商品を含むブログを見る