2011-09-14 20 views
5

Tengo dificultades para descifrar una lista de Ints en una tupla que contiene dos listas nuevas, de modo que cada elemento (comenzando por el primero) va a la primera lista y cada otro elemento en el segundo.Haskell: dividiendo la lista en tupla de dos listas nuevas

así:

split [] = ([],[]) 
split [1] = ([1],[]) 
split [1,2] = ([1],[2]) 
split [1,2,3] = ([1,3],[2]) 
split [1,2,3,4] = ([1,3],[2,4]) 

que estoy tratando de lograr esto de forma recursiva (con guardias) y sólo utilizando los argumentos individuales XS

Este es mi enfoque que se pone cada vez mensajes de error:

split :: [Int] -> ([Int],[Int]) 
split xs | length(xs) == 0 = ([],[]) 
     | length(xs) == 1 = (xs !! 0 : [],[]) 
     | length(xs) == 2 = (xs !! 0 : [], xs !! 1 : []) 
     | otherwise = (fst ++ xs !! 0, snd ++ xs !! 1) ++ split(drop 2 xs))  
+0

Gracias chicos! – Shabu

+1

Debe aceptar una de las respuestas. –

Respuesta

14

Su función split devuelve un par, pero en el último caso está utilizando ++ en el resultado de split. Eso será un error de tipo, ya que ++ funciona en listas, no en pares. También hay un error de tipo porque fst y snd son funciones para seleccionar los elementos de un par, pero los está utilizando de una manera extraña.

Además, utilice la coincidencia de patrones en lugar de usar la longitud. Además, el caso donde prueba si la longitud es 2 no es necesario, ya que el caso general elimina 2 elementos que lo llevan al caso base de la lista vacía.

También puede hacer que su función sea más general utilizando una variable de tipo a en lugar de Int en el tipo.

[Editar]: se agrega código

split :: [a] -> ([a], [a]) 
split [] = ([], []) 
split [x] = ([x], []) 
split (x:y:xys) = (x:xs, y:ys) where (xs, ys) = split xys 
+1

Alternativamente, 'split (z: zs) = (z: ys, xs) donde (xs, ys) = split zs'! – Zantier

0

Hay un error en la última cláusula. Debe obtener los resultados de la llamada recursiva y luego agregarle el primer y segundo elemento.

split :: [Int] -> ([Int],[Int]) 
split xs | length(xs) == 0 = ([],[]) 
     | length(xs) == 1 = (xs !! 0 : [],[]) 
     | length(xs) == 2 = (xs !! 0 : [], xs !! 1 : []) 
     | otherwise = let (fst, snd) = split(drop 2 xs) in 
        (xs !! 0 : fst, xs !! 1 : snd) 
+0

Esta es una forma horrible de escribir esta función. – augustss

+0

Sí, tienes toda la razón. Pero estoy tratando de seguir la pregunta 'para lograr esto de manera recursiva (con guardias) y solo usando el argumento único xs' – bravit

+1

. Todavía puede hacer eso y obtener O (n) complejidad en lugar de O (n^2). – augustss

3
split :: [a] -> ([a], [a]) 
split xs | null xs = ([], []) 
     | otherwise = (head xs : snd pair, fst pair) 
    where pair = split (tail xs) 

Pero usted debe utilizar un pliegue:

split :: [a] -> ([a], [a]) 
split = foldr (\x (ys, zs) -> (x : zs, ys)) ([], []) 
+0

Ese código no hace lo que pidió, y también es malo porque usa 'head' y' tail' en lugar de coincidencia de patrones. – augustss

+0

Podría dar un ejemplo de una entrada en la que mi código arroja un resultado incorrecto, por favor. (¿Y te refieres a la versión de recursivas y guardias o la versión de foldr?) Estoy de acuerdo en que la coincidencia de patrones sería mejor que 'head' y' tail', pero el OP parece querer usar guardias, que --- ** en este caso ** --- impide la coincidencia de patrones (no queda nada por guardar después de la coincidencia del patrón). – dave4420

+1

Lo siento, me refiero a que está mal. No hay suficiente café :) – augustss

0

Si estás buscando un poco de forma alternativa a ello, a continuación es uno de esos aplicación:

split xs = 
    let (a,b) = partition (odd . snd) (zip xs [1..]) 
    in ((map fst a), (map fst b)) 
1

Dos versiones alternativas:

split = conv . map (map snd) . groupWith (even.fst) . zip [0..] where 
    conv [xs,ys] = (xs,ys) 

split xs = (ti even xs, ti odd xs) where 
    ti f = map snd . filter (f.fst) . zip [0..] 
5

Otra forma de hacerlo es con la recursión mutua. Sale a la luz muy fácil de leer:

split xs = (odds xs, evens xs) 

odds (x:xs) = x : evens xs 
odds xs  = [] 

evens xs = odds (drop 1 xs) 
2

El Blow Your Mind wiki de Haskell, tiene algunos trazadores de líneas uno:

-- splitting in two (alternating) 
-- "1234567" -> ("1357", "246") 

-- the lazy match with ~ is necessary for efficiency, especially enabling 
-- processing of infinite lists 
foldr (\a ~(x,y) -> (a:y,x)) ([],[]) 

(map snd *** map snd) . partition (even . fst) . zip [0..] 

transpose . unfoldr (\a -> toMaybe (null a) (splitAt 2 a)) 
Cuestiones relacionadas