una tres suma rotacion promedio numeros mayor listas lista eliminar elemento contadores comparar haskell

haskell - tres - ¿Cómo puedo obtener el n-ésimo elemento de una lista?



rotacion de listas en haskell (6)

El tipo de datos de lista estándar de Haskell para todos forall t. [t] forall t. [t] en la implementación se parece mucho a una lista canónica de enlaces C, y comparte sus propiedades esencialmente. Las listas vinculadas son muy diferentes de las matrices. En particular, el acceso por índice es una operación O (n) lineal, en lugar de O (1) de tiempo constante.

Si necesita acceso aleatorio frecuente, considere el estándar Data.Array .

!! es una función insegura parcialmente definida, lo que provoca un colapso de los índices fuera de rango. Tenga en cuenta que la biblioteca estándar contiene algunas funciones parciales ( head , last , etc.). Para mayor seguridad, use un tipo de opción Maybe o el módulo Safe .

Ejemplo de una función de indexación razonablemente eficaz, robusta (para índices ≥ 0):

data Maybe a = Nothing | Just a lookup :: Int -> [a] -> Maybe a lookup _ [] = Nothing lookup 0 (x : _) = Just x lookup i (_ : xs) = lookup (i - 1) xs

Trabajando con listas enlazadas, a menudo los ordinales son convenientes:

nth :: Int -> [a] -> Maybe a nth _ [] = Nothing nth 1 (x : _) = Just x nth n (_ : xs) = nth (n - 1) xs

¿Cómo puedo acceder a una lista por índice en Haskell, análogo a este código C?

int a[] = { 34, 45, 56 }; return a[1];


La respuesta directa ya fue dada: !! Use !! .

Sin embargo, los novatos a menudo tienden a abusar de este operador, que es caro en Haskell (porque trabajas en listas vinculadas individuales, no en matrices). Hay varias técnicas útiles para evitar esto, la más fácil es usar zip. Si escribe zip ["foo","bar","baz"] [0..] , obtiene una nueva lista con los índices "adjuntos" a cada elemento de un par: [("foo",0),("bar",1),("baz",2)] , que a menudo es exactamente lo que necesita.


Mira here , operador !! .

Es decir, [1,2,3]!!1 le da 2 , ya que las listas están indexadas en 0.


No estoy diciendo que su pregunta o la respuesta sean incorrectas, pero tal vez le gustaría saber sobre la maravillosa herramienta que es Hoogle para ahorrarse tiempo en el futuro: con Hoogle, puede buscar funciones de biblioteca estándar que coinciden con una firma determinada. ¡Entonces, sin saber nada !! , en su caso, podría buscar "algo que tome una Int y una lista de elementos que regresen una y tal como sea", es decir,

Int -> [a] -> a

Lo y behold , con !! como el primer resultado (aunque la firma de tipo en realidad tiene los dos argumentos en reversa en comparación con lo que buscamos). Limpio, ¿eh?

Además, si su código se basa en la indexación (en lugar de consumir desde el principio de la lista), las listas pueden no ser la estructura de datos adecuada. Para O (1) acceso basado en índices hay alternativas más eficientes, como arrays o vectors .


Puedes usar !! , pero si quieres hacerlo de manera recursiva, a continuación hay una forma de hacerlo:

dataAt :: Int -> [a] -> a dataAt _ [] = error "Empty List!" dataAt y (x:xs) | y <= 0 = x | otherwise = dataAt (y-1) xs


Una alternativa al uso (!!) es usar el paquete de lens y su función de element y operadores asociados. La lens proporciona una interfaz uniforme para acceder a una amplia variedad de estructuras y estructuras anidadas más allá de las listas. A continuación me centraré en proporcionar ejemplos y pasaré por alto las firmas de tipo y la teoría detrás del paquete de lens . Si desea saber más sobre la teoría, un buen lugar para comenzar es el archivo léame en el repositorio github .

Acceder a listas y otros tipos de datos

Obtener acceso al paquete de lentes

En la línea de comando:

$ cabal install lens $ ghci GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help Loading package ghc-prim ... linking ... done. Loading package integer-gmp ... linking ... done. Loading package base ... linking ... done. > import Control.Lens


Accediendo a las listas

Para acceder a una lista con el operador infijo

> [1,2,3,4,5] ^? element 2 -- 0 based indexing Just 3

A diferencia del (!!) esto no arrojará una excepción al acceder a un elemento fuera de límites y devolverá Nothing lugar. A menudo se recomienda evitar funciones parciales como (!!) o head ya que tienen más casos de esquina y es más probable que causen un error de tiempo de ejecución. Puede leer un poco más sobre por qué para evitar funciones parciales en esta página wiki .

> [1,2,3] !! 9 *** Exception: Prelude.(!!): index too large > [1,2,3] ^? element 9 Nothing

Puede forzar la técnica de la lente para que sea una función parcial y lanzar una excepción cuando esté fuera de límites utilizando el operador (^?!) lugar del operador (^?) .

> [1,2,3] ^?! element 1 2 > [1,2,3] ^?! element 9 *** Exception: (^?!): empty Fold


Trabajar con tipos distintos de listas

Sin embargo, esto no solo se limita a las listas. Por ejemplo, la misma técnica funciona en trees del paquete de containers estándar.

> import Data.Tree > :{ let tree = Node 1 [ Node 2 [Node 4[], Node 5 []] , Node 3 [Node 6 [], Node 7 []] ] :} > putStrLn . drawTree . fmap show $tree 1 | +- 2 | | | +- 4 | | | `- 5 | `- 3 | +- 6 | `- 7

Ahora podemos acceder a los elementos del árbol en primer orden:

> tree ^? element 0 Just 1 > tree ^? element 1 Just 2 > tree ^? element 2 Just 4 > tree ^? element 3 Just 5 > tree ^? element 4 Just 3 > tree ^? element 5 Just 6 > tree ^? element 6 Just 7

También podemos acceder a las sequences del paquete de containers :

> import qualified Data.Sequence as Seq > Seq.fromList [1,2,3,4] ^? element 3 Just 4

Podemos acceder a las matrices indexadas int estándar del paquete vectors , al texto del paquete de text estándar, a las cadenas de bytestring paquete de bytestring estándar y a muchas otras estructuras de datos estándar. Este método estándar de acceso se puede extender a sus estructuras de datos personales convirtiéndolos en una instancia de la clase de tipos Taversable , consulte una lista más larga de ejemplos de Traversables en la documentación de Lens. .


Estructuras anidadas

Cavar en estructuras anidadas es simple con el hackage de lentes. Por ejemplo, acceder a un elemento en una lista de listas:

> [[1,2,3],[4,5,6]] ^? element 0 . element 1 Just 2 > [[1,2,3],[4,5,6]] ^? element 1 . element 2 Just 6

Esta composición funciona incluso cuando las estructuras de datos anidados son de diferentes tipos. Entonces, por ejemplo, si tuviera una lista de árboles:

> :{ let tree = Node 1 [ Node 2 [] , Node 3 [] ] :} > putStrLn . drawTree . fmap show $ tree 1 | +- 2 | `- 3 > :{ let listOfTrees = [ tree , fmap (*2) tree -- All tree elements times 2 , fmap (*3) tree -- All tree elements times 3 ] :} > listOfTrees ^? element 1 . element 0 Just 2 > listOfTrees ^? element 1 . element 1 Just 4

Puede anidar arbitrariamente profundamente con tipos arbitrarios siempre que cumplan con el requisito de Traversable . Así que acceder a una lista de árboles de secuencias de texto no es sudar.


Cambiar el enésimo elemento

Una operación común en muchos idiomas es asignar a una posición indexada en una matriz. En python puedes:

>>> a = [1,2,3,4,5] >>> a[3] = 9 >>> a [1, 2, 3, 9, 5]

El paquete de lens brinda esta funcionalidad con el operador (.~) . Aunque a diferencia de Python, la lista original no está mutada, más bien se devuelve una nueva lista.

> let a = [1,2,3,4,5] > a & element 3 .~ 9 [1,2,3,9,5] > a [1,2,3,4,5]

element 3 .~ 9 es solo una función y el operador (&) , parte del paquete de lens , es solo aplicación de función inversa. Aquí está con la aplicación de función más común.

> (element 3 .~ 9) [1,2,3,4,5] [1,2,3,9,5]

La asignación nuevamente funciona perfectamente bien con el anidamiento arbitrario de Traversable s.

> [[1,2,3],[4,5,6]] & element 0 . element 1 .~ 9 [[1,9,3],[4,5,6]]