2016-05-18 7 views
2

は私がハスケルのリストにいくつかの文字列を "パック"するには?

pack ['a','a','a','b','c','c','a','a','d','e','e','e'] 
= ["aaa","b","cc","aa","d","eee"] 

がどのように私はこれを行うことができるような機能パックを書きたいですか?私がこだわっている...

+1

"教科書"の問題に取り組んでいるなら、[99ハスケルの問題](https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems)に慣れるのは良いことです。これは問題9であり、ソリューションページには[それを行うためのいくつかの方法](https://wiki.haskell.org/99_questions/Solutions/9)(それぞれの場合と同じように)が表示されています。 – HostileFork

答えて

1

はここに私の頭の上から何か:

pack :: (Eq a) => [a] -> [[a]] 
pack [] = [] 
-- We split elements of a list recursively into those which are equal to the first one, 
-- and those that are not. Then do the same for the latter: 
pack (x:xs) = let (first, rest) = span (==x) xs 
       in (x:first) : pack rest 

Data.Listすでにしかし、あなたが探しているものがあります。

2

使用Data.List.group

λ> import Data.List (group) 
λ> :t group 
group :: Eq a => [a] -> [[a]] 
λ> group ['a','a','a','b','c','c','a','a','d','e','e','e'] 
["aaa","b","cc","aa","d","eee"] 

あなたが機能を自分で書きたい場合を除き(Michael Foukarakis answerを参照)

0

私はそれがより明示的な/初心者のバージョンを追加する価値があると思う:

pack :: [Char] -> [String] 
pack [] = [] 
pack (c:cs) = 
    let (v, s) = findConsecutive [c] cs 
    in v : pack s 
    where 
    findConsecutive ds [] = (ds, []) 
    findConsecutive [email protected](d:ds) [email protected](e:es) 
     | d /= e = (s, t) 
     | otherwise = findConsecutive (e:s) es 

場合入力は空のリストであり、結果も空のリストです。それ以外の場合は、次の連続したCharが同じであることがわかり、Stringにグループ化され、結果リストに戻されます。そのためには、補助機能のfindConsecutiveを使用します。この関数の動作は、使用する述語(等価比較)を事前に知っていることと、消費されたリストと残りのリストの両方を返すという違いがあり、takeWhile関数に似ています。すなわち

findConsecutiveの署名は、以下のように書くことができる:それはアキュムレータと、その文字「抽出」されているリストとして使用するだけ繰り返し文字を含む文字列をとることを意味

findConsecutive :: String -> [Char] -> (String, String) 

から。現在の要素のシーケンスと残りのリストを含むタプルを返します。文字リストは空ではなく、現在の要素はアキュムレータのものと同じですが、文字をアキュムレータに追加し、関数に再帰的に追加します。この関数は、リストの最後に到達するか、別の文字に遭遇したときに戻ります。

packの本文を理解するのに同じ理由が使用できます。

関連する問題