2010-01-24 15 views
5

Come posso scrivere una funzione in Haskell, che accetta una stringa di input nel formato a1a2a3 e si espande in a1a2a2a3a3a3. Ad esempio, la stringa di input "codice" verrà espansa in "coodddeeee"Apprendimento Haskell: domanda di manipolazione stringa

+0

Si prega di inserire il codice che hai scritto per risolvere questo finora. Altrimenti la gente potrebbe sospettare che questo è compito. –

+0

Ti assicuro, questo non è compito a casa :) Stavo lavorando attraverso le excersises in un libro di Haskell e il mio cervello si è appena congelato su questo. Tutto quello che so a questo punto è che dovrò usare l'operatore ++, una specie di manipolazione di array e usare la funzione di lunghezza –

risposta

9

Probabilmente molto inefficiente :)

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: la giustapposizione si lega più strettamente di qualsiasi altra cosa ma @, quindi puoi rimuovere alcune parentesi troppo paranoiche. f n (c: s) = replicare n C++ f (n + 1) s –

19

Quindi si desidera il carattere nth ripetuto n volte.

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

Sono sicuro che c'è un modo più semplice per farlo.

Spiegazione: Per prima cosa prendiamo la stringa e la associamo alla sua posizione nell'elenco (a partire da 1). Questo è ciò che fa zip:

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

Ora la funzione g (x,y) utilizza la funzione di replica, che replica quello che vuoi y volte. Quindi replichiamo x, y volte.

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

Se mappiamo questa funzione sopra la lista prodotta ad ottenere il risultato:

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

Se si dispone di una lista di stringhe, è possibile concatenare insieme utilizzando concat. concatMap applica la funzione g a ciascuna coppia di lettere e numeri e quindi concatena la stringa nel risultato finale.

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

In sostanza: concat $ map g ->concatMap g

EDIT: ora funziona, può anche essere fatto in una sola riga nel seguente modo:

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

uscita:

Prelude> f "lambda" 
"laammmbbbbdddddaaaaaa" 
+0

Jonno ... Puoi spiegare quella risposta, Come qualcuno che si trova nelle primissime fasi di imparando haskell, la risposta di cui sopra non ha senso per me. –

+0

Vedere la modifica per la spiegazione –

+2

Sostituire 'g' con' uncurry. flip replicate'. Fa la stessa cosa, ma usa le funzioni standard della libreria Haskell. –

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

cede

Main> f "code" 
"coodddeeee" 
+1

Bello! Per quelle persone come me, che non conoscono il tipo di operatore: "Composizione Kleisli da sinistra a destra delle monade:' (> =>) :: 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

Perché la gente odia list comprehension?

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

o se si vuole impazzire con le estensioni

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