2010-12-20 19 views
7

Lisp sınıfı için, Haskell'de de çözmeyi denediğim basit bir sıraya dönüştürme şifresi ödevi verildi. Temel olarak, biri bir dizeyi n uzunluğundaki satırlara böler ve sonra sonucu aktarır. Sonuç listesi listelerinin birleştirilmiş listesi şifrelenmiş dizedir. Kod çözme biraz daha zordur, çünkü en son girdi satırında eksik olan elemanlar (sonuçta eksik sütunlar) bulunmalıdır.Basit satır aktarım şifresi

Bu Haskell benim çözümdür:

import Data.List 
import Data.Ratio 
import Data.List.Split 

encode :: String -> Int -> String 
encode s n = concat . transpose $ chunk n s 

decode :: String -> Int -> String 
decode s n = take len $ encode s' rows 
    where s'  = foldr (insertAt " ") s idxs 
      rows = ceiling (len % n) 
      idxs = take (n-filled) [n*rows-1,(n-1)*rows-1..] 
      filled = len - n * (rows - 1) 
      len = length s 

insertAt :: [a] -> Int -> [a] -> [a] 
insertAt xs i ys = pre ++ xs ++ post 
    where (pre,post) = splitAt i ys 

İş yok, ama bu benim çok deklaratif hissetmez endeksleri ile işe yaramaz, çünkü deyimsel Haskell olarak kabul edilip, emin değilim. Bu geliştirilebilir mi ve eğer evet ise, nasıl? Bu arada

: Haskell 98 yılında insertAt benzer bir şey var mı? Yani Verilen bir endekste bir eleman veya listeyi bir listeye ekleyen bir işlev.

Not: Bu arada bugün kaynaklandığını ödev, bir parçası değildir.

+1

Küçük bir açıklama: yazabilirsiniz idxs = [n * satır-1, (n-1) * satır-1 .. (dolu + 1) * satır-1] '. – HaskellElephant

+0

@HaskellElephant: Güzel görünüyor, teşekkürler! – danlei

cevap

5

Bunu, encode ve decode sorunlarına hafifçe farklı bir şekilde bakarak yaparım. encode, verileri daha sonra bir n-kolon matrisine böler ve daha sonra satırlara sıralar ve bir n -row matrisine dönüştürür. decode, verileri daha sonra bir n satır matrisine böler ve ardından satırları sırayla birleştirir (n sütun matrisine dönüştürür).

Yani iki işlevi tanımlayarak başlamak istiyorum - Bir n sütun matris içine bir dizi yapmak için: biri

chunk:: Int -> [a] -> [[a]] 
chunk n as = chunk' n (length as) as 
    where chunk' n l as | l <= n = [as] 
         | otherwise = some : chunk' n (l-n) rest 
          where (some, rest) = splitAt n as 

ve başka bir n satır matris içine bir dizi dilim:

slice :: Int -> [a] -> [[a]] 
slice n as = chunk (q+1) front ++ chunk q back 
    where (q,r) = length as `divMod` n 
     (front, back) = splitAt (r*(q+1)) as 

Şimdi kodlama ve kod çözme işlemi oldukça kolaydır:

encode :: Int -> [a] -> [a] 
encode = ((concat . transpose) .). chunk 
decode :: Int -> [a] -> [a] 
decode = ((concat . transpose) .). slice 
+0

Teşekkürler! Küçük düzeltme: 'chunk' 'ibaresinin ikinci muhafızında 'chunk' 'yazmalıdır. – danlei

+0

@danlei: teşekkürler! sabit. – rampion

+0

1 (((concat. Transpose).). Chunk) == (\ x -> \ y -> concat (aktarım (yığın x y))))? – adamse

İlgili konular