How can I get nth element from a list?

Look here, the operator used is !!.

I.e. [1,2,3]!!1 gives you 2, since lists are 0-indexed.


An alternative to using (!!) is to use the lens package and its element function and associated operators. The lens provides a uniform interface for accessing a wide variety of structures and nested structures above and beyond lists. Below I will focus on providing examples and will gloss over both the type signatures and the theory behind the lens package. If you want to know more about the theory a good place to start is the readme file at the github repo.

Accessing lists and other datatypes

Getting access to the lens package

At the command line:

$ 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


Accessing lists

To access a list with the infix operator

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

Unlike the (!!) this will not throw an exception when accessing an element out of bounds and will return Nothing instead. It is often recommend to avoid partial functions like (!!) or head since they have more corner cases and are more likely to cause a run time error. You can read a little more about why to avoid partial functions at this wiki page.

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

> [1,2,3] ^? element 9
Nothing

You can force the lens technique to be a partial function and throw an exception when out of bounds by using the (^?!) operator instead of the (^?) operator.

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


Working with types other than lists

This is not just limited to lists however. For example the same technique works on trees from the standard containers package.

 > 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

We can now access the elements of the tree in depth-first order:

> 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

We can also access sequences from the containers package:

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

We can access the standard int indexed arrays from the vector package, text from the standard text package, bytestrings fro the standard bytestring package, and many other standard data structures. This standard method of access can be extended to your personal data structures by making them an instance of the typeclass Taversable, see a longer list of example Traversables in the Lens documentation..


Nested structures

Digging down into nested structures is simple with the lens hackage. For example accessing an element in a list of lists:

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

This composition works even when the nested data structures are of different types. So for example if I had a list of trees:

> :{
 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

You can nest arbitrarily deeply with arbitrary types as long as they meet the Traversable requirement. So accessing a list of trees of sequences of text is no sweat.


Changing the nth element

A common operation in many languages is to assign to an indexed position in an array. In python you might:

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

The lens package gives this functionality with the (.~) operator. Though unlike in python the original list is not mutated, rather a new list is returned.

> 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 is just a function and the (&) operator, part of the lens package, is just reverse function application. Here it is with the more common function application.

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

Assignment again works perfectly fine with arbitrary nesting of Traversables.

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

I'm not saying that there's anything wrong with your question or the answer given, but maybe you'd like to know about the wonderful tool that is Hoogle to save yourself time in the future: With Hoogle, you can search for standard library functions that match a given signature. So, not knowing anything about !!, in your case you might search for "something that takes an Int and a list of whatevers and returns a single such whatever", namely

Int -> [a] -> a

Lo and behold, with !! as the first result (although the type signature actually has the two arguments in reverse compared to what we searched for). Neat, huh?

Also, if your code relies on indexing (instead of consuming from the front of the list), lists may in fact not be the proper data structure. For O(1) index-based access there are more efficient alternatives, such as arrays or vectors.

Tags:

Haskell