2010-01-24 16 views
5

Haskell'de, a1a2a3 biçiminde bir girdi dizesi alan ve a1a2a2a3a3a3'e genişleyen bir işlevi nasıl yazabilirim. Örneğin, giriş dizgisi "kod", "coodddeeee"Öğrenme Haskell: String manipülasyon sorusu

+0

Eğer şimdiye kadar bu çözmek için yazdım kod sonrası Lütfen deli gitmek istiyorum. Aksi halde insanlar bunun ev ödevi olduğundan şüphelenebilirler. –

+0

Sizi temin ederim, bu ev ödevi değildir :) Bir Haskell kitabındaki excersises aracılığıyla çalışıyordum ve beynim bunun üzerinde donuyordu. Bu noktada bildiğim şu ki, ++ operatörünü kullanmam gerekecek, bir çeşit dizi manipülasyonu ve olası uzunluk fonksiyonunu kullanabileceğim –

cevap

9

Muhtemelen çok verimsiz :)

f :: Int -> [Char] -> [Char] 
f _ [] = [] 
f n (c:s) = (replicate n c) ++ (f (n+1) s) 

g :: [Char] -> [Char] 
g s = f 1 s 

.

*Main> g "code" 
"coodddeeee" 
+5

FYI: juxtaposition herşeyden daha sıkı bağlar ama @, Birkaç aşırı paranoyak parantezi kaldırabilirsiniz. f n (c: s) = çoğaltma n C++ f (n + 1) s –

19

'a genişletilecektir. Böylece karakterinin n kez tekrarlanmasını istiyorsunuz.

f :: String -> String 
f x = concatMap g (zip x [1..]) 
    where 
     g (x,y) = replicate y x 

Bunun için daha kolay bir yol olduğundan eminim.

Açıklama: Önce dizeyi alıp listedeki yeriyle eşleştirelim (1'den başlayarak). Bu ne fermuar geçerli:

Prelude> zip "code" [1..] 
[('c',1),('o',2),('d',3),('e',4)] 

Şimdi fonksiyon g (x,y) Eğer y defa istediğini kopyalayan çoğaltmak işlevini kullanır. Yani x, y kere çoğaltırız.

Prelude> map g $ zip "code" [1..] 
["c","oo","ddd","eeee"] 

Dizgilerde bir listesi varsa, bunları concat kullanarak birlikte arada kullanabilirsiniz: ürettiğimiz liste üzerinde bu işlevi eşlerseniz

Prelude> g ('z',4) 
"zzzz" 

sonuç almak. concatMap, her bir harf ve sayı çiftine g işlevini uygular ve ardından dizeyi son sonuca birleştirir.

Prelude> concat $ map g $ zip "code" [1..] 
"coodddeeee" 

Temelde: concat $ map g ->concatMap g

DÜZENLEME: çalıştığını şimdi, o da thusly bir satırda yapılabilir:

f x = concatMap (\(a,b)->replicate b a) $ zip x [1..] 

Çıktı:

Prelude> f "lambda" 
"laammmbbbbdddddaaaaaa" 
+0

Jonno ... Bu cevabı açıklayabilir misiniz, Birinin çok erken aşamalarında olan biri olarak haskell'i öğrenmek, yukarıdaki cevap sadece bana mantıklı gelmiyor. –

+0

Açıklama için düzenlemeye bakın –

+2

'g' uncurry ile değiştirilmem gerekir. kopyala. Aynı şeyi yapar, ancak standart Haskell kitaplığı işlevlerini kullanır. –

15
import Control.Monad 
f = zip [1..] >=> uncurry replicate 

Main> f "code" 
"coodddeeee" 
+1

Güzel! Benim gibi insanlar için, operatörün tipini bilmeyenler için: "Soldan sağa Monasların bileşimi:" (> =>) :: Monad m => (a -> mb) -> (b -> mc) -> (a -> mc) '" –

1
Prelude> let l = "code" in concat $ [take y $ repeat (last $ take y l) | y <- [1..length l]] 
"coodddeeee" 
4

İnsanlar neden Liste comprehensions nefret ediyorsun verir?

Prelude> let f s = concat [ replicate x y | (x,y) <- zip [1..] s] 
Prelude> f "code" 
"coodddeeee" 

veya uzantıları

Prelude> :set -XParallelListComp 
Prelude> let f s = concat [ replicate x y | x <- [1..] | y <- s] 
Prelude> f "code" 
"coodddeeee"