2011-09-11 55 views
19

¿Cuál es la forma más rápida de obtener el último elemento de una lista en Haskell? También en la siguiente iteración, quiero eliminar el primer y el último elemento de la lista. ¿Cuál es la forma más elegante de hacerlo? Estoy intentando la comprensión de la lista, ¡pero eso no parece muy eficiente!La forma más rápida de obtener el último elemento de una lista en Haskell

+3

Creo que la recuperación de la última * * elemento de manera eficiente es difícil. Tal vez deberías explicar el contexto con más detalle, para que puedas ver si hay otras estructuras de datos que se ajusten mejor a tus necesidades. – phimuemue

+1

hay pocas razones para dudar de que Prelude.last tenga una buena implementación. La mejor pregunta, como dice phimuemue, es si, si estás usando 'last' mucho, no necesitas otra cosa que listas, p. Data.Sequence o algo por el estilo. – applicative

Respuesta

32

last y init harán bien el trabajo por una sola vez. Sin embargo, ambos son O (n), por lo que si necesita manipular ambos extremos de una lista a menudo, como parece implicar, puede considerar usar Data.Sequence, que admite O (1) inserción y eliminación de artículos en ambos extremos.

67

Puede usar the last function para obtener el último elemento de una lista.

En cuanto a cómo eliminar los elementos primero y último, puede usar (init . tail), pero no sé cuán eficiente es eso.

Creo que esta imagen de Learn You A Haskell muestra las funciones de lista bastante bien:

illustration of list functions

+0

¿No es '(init. Tail)' incorrecto/erróneo? Debería ser '(head. Tail)'. – nulvinge

+1

@nulvinge (head. Tail) simplemente devolvería el segundo elemento en la lista. Ver la imagen de arriba :) – Phyx

+0

Ops, lo siento, tienes razón. Estado haciendo mucho esquema últimamente para reconocer. como composición ... – nulvinge

0

Para eliminar primera y última:

take (len(l)-2) (drop 1 l) 

o tal vez

init (drop 1 l) 

Esto también da como resultado un código casi óptimo.

5

Voy a publicar la aplicación Preludio ya que no se ha publicado aún:

listLast :: [a] -> a 
listLast [x] = x --base case is when there's just one element remaining 
listLast (_:xs) = listLast xs --if there's anything in the head, continue until there's one element left 
listLast [] = error "Can't do last of an empty list!" 

Tenga en cuenta que he cambiado el nombre de la función a listLast de manera que se pueda ejecutar sin entrar en conflicto con el preludio normal. Podría, por supuesto, hacer import Prelude hiding(last).

+0

La convención que usa en este http://learnyouahaskell.com/chapters es 'last'' – CSharper

-2
(head.reverse) [1..100] 

Es una alternativa al last para obtener el último elemento.

drop 1 (take (length [1..100] - 1) [1..100]) 

elimina el elemento de lista primero y el último. La fuente para drop y take parece que podría ser más rápido que (init . tail).

(reverse.drop 1) ((reverse.drop 1) [1..100]) 

es otra variante. Pero creo que es más lento debido a la doble inversión.

+1

' length' rara vez es algo que desea hacer sin una buena razón. No hay una buena razón aquí. Lo mismo ocurre con 'reverse'. – dfeuer

0

Esta respuesta se enfoca en tratar condiciones extrañas (como listas vacías) de una manera máximamente flexible, y en crear funciones más grandes desde las más pequeñas usando algunas funciones de la biblioteca. Es no la mejor respuesta para alguien que primero conoce las listas, pero un par de pasos más allá de eso.

Para lo siguiente, necesitará

import Control.Monad ((>=>)) 

y tendrá que usar ya sea GHC 7.10 e importar Data.List (uncons) o definir

uncons :: [a] -> Maybe (a, [a]) 
uncons [] = Nothing 
uncons (x:xs) = Just (x,xs) 

Se puede escribir una forma segura de init así:

init' :: [x] -> Maybe [x] 
init' = foldr go Nothing 
    where 
    go x mxs = Just (maybe [] (x:) mxs) 

Una versión de tail puede escribirse

tail' :: [a] -> Maybe [a] 
tail' = fmap snd . uncons 

Así entonces se puede obtener un tal vez

trim' :: [a] -> Maybe [a] 
trim' = init' >=> tail' 

El >=> es una especie de composición monádica hacia atrás. init' >=> tail' es una función que aplica init' a su argumento para obtener un Maybe [a]. Si obtiene Nothing, lo devuelve. Si obtiene Just xs, aplica tail' a xs y lo devuelve.

partir de esto, usted puede hacer fácilmente un condensador de ajuste que recorta las listas con 0, 1 ó 2 elementos a listas vacías:

trim :: [a] -> [a] 
trim = maybe [] id . trim' 
Cuestiones relacionadas