2009-06-24 17 views
6

Estoy leyendo a través de Learn You a Haskell y llegué a un punto en el que estoy tratando de mover un elemento de una lista a la cabeza. He descubierto lo que creo que es la manera ingenua y tengo curiosidad si alguien puede mostrarme lo que haría el experimentado programador Haskell en su lugar.¿Cómo mover un elemento en una lista en Haskell?

En este ejemplo, tengo una lista de enteros y quiero mover el elemento '4', que sería el índice '3', al encabezado de la lista.

let nums = [1, 2, 3, 4, 5] 
(nums !! 3) : delete (nums !! 3) nums 

devuelve [4, 1, 2, 3, 5].

¿Qué opinas?

+3

"Borrar" elimina la primera aparición del elemento dado, por lo que podría eliminar el elemento equivocado si hay duplicados ... – sth

Respuesta

15

lo haría de esta manera:

move n as = head ts : (hs ++ tail ts) 
    where (hs, ts) = splitAt n as 

splitAt divide una lista en la posición dada, devuelve las dos partes que son creados por la división (aquí hs y ts). El elemento que debe moverse al frente ahora está al comienzo de ts. head ts devuelve solo este primer elemento de ts, tail ts devuelve todo pero ese primer elemento. El resultado de la función son solo estas partes combinadas en el orden correcto: hs concatenado con tail ts y precedido por el elemento head ts.

+3

toHead n l = let (xs, y: ys) = splitAt n l en y: xs ++ ys – Stephan202

+0

sth: ¿Podría describirlo para comprender el código? – shahkalpesh

0

¿Qué coincidencia?
Estaba leyendo lo mismo hace unos días. Lo buscó de nuevo & lo escribió como sigue.

nums !! 3 : [x | x <- nums, (x == (num !! 3)) == False] 
+0

Dos problemas: Primero, se eliminan los elementos duplicados. Segundo (menos problema), el operador no igual es (/ =), en lugar de ((a == b) == Falso). –

+0

Buena captura. Como puedes ver, soy un principiante.Gracias por corregir :) – shahkalpesh

11

Haskellers con experiencia casi nunca utiliza la indexación de listas. Que haría uso de ruptura para evitar recorridos repetidos (suponiendo que desea hacer coincidir el elemento de '4', no index '3'):

case break (== 4) [1, 2, 3, 4, 5] of 
    (a,x:xs) -> x:a ++ xs 
    (a,xs) -> a ++ xs 

Como en:

Prelude Data.List> case break (== 4) [1, 2, 3, 4, 5] of (a,x:xs) -> x:a ++ xs; (a,xs) -> a ++ xs 
[4,1,2,3,5] 

Podemos hacer lo mismo con la indexación a través de 'splitAt':

Prelude Data.List> case splitAt 3 [1, 2, 3, 4, 5] of (a,x:xs) -> x:a ++ xs; (a,xs) -> a ++ xs 
[4,1,2,3,5] 
+0

Sí, coincide en el elemento 4 que no está en el índice '3'. Perdón por la confusión – afrosteve

3

también hay

toHead n l = l !! n : take n l ++ drop (n+1) l 

que puede ser un poco más fácil de seguir que usando splitAt.

+0

¿no es esto más lento que la versión splitAt? – yairchu

+0

No está claro después de que el optimizador haya terminado. Ejecutar con ghc -O y descubrirlo! –

+0

¿Esto haría 2 pases sobre la lista? – Daniel

8

pequeña modificación en la solución de algo:

toHead n xs = x : pre ++ post 
    where (pre, x:post) = splitAt n xs 

usando coincidencia de patrones en lugar de head n tail

+1

Creo que esta es la solución más fácil de entender. Buen toque con el patrón de coincidencia! – Michael

Cuestiones relacionadas