How to edit the nth item in a Haskell list?

I know xs !! n gives me the nth element in the list, but I don't know how to edit the nth element in this list. Can you tell me how I can change the nth element in the list or give at least a hint? For example, how can I make the second element of 'a' a 'e' in this: ['s', 't', 'a', 'c', 'k']? Thanks.

+6
source share
3 answers

Since Haskell is a functional language, you cannot edit items in lists because everything is the same. Instead, you can create a new list with something like:

take n xs ++ [newElement] ++ drop (n + 1) xs 

However, this is not recommended in Haskell. For more information, you can see this message: Haskell replace the item in the list

+8
source

Changing the nth item

A common operation in many languages ​​is the assignment of an indexed position in an array. In python you can:

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

The lens package provides this functionality to the operator (.~) . Although, unlike python, the original list is not mutated, the new list is more likely to return.

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

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

The assignment works fine again with Traversable s arbitrary nesting.

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

or

 > set (element 3) 9 [1,2,3,4,5,6,7] 

Or, if you want to use several elements that you can use:

 > over (elements (>3)) (const 99) [1,2,3,4,5,6,7] > [1,2,3,4,99,99,99] 

Work with other types of lists

This is not limited to lists, however, it will work with any data type that is an instance of the Traversable typeclass.

Take, for example, the same technique that works on container trees.

  > 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 > putStrLn . drawTree . fmap show $ tree & element 1 .~ 99 1 | +- 99 | | | +- 4 | | | `- 5 | `- 3 | +- 6 | `- 7 > putStrLn . drawTree . fmap show $ tree & element 3 .~ 99 1 | +- 2 | | | +- 4 | | | `- 99 | `- 3 | +- 6 | `- 7 > putStrLn . drawTree . fmap show $ over (elements (>3)) (const 99) tree 1 | +- 2 | | | +- 4 | | | `- 5 | `- 99 | +- 99 | `- 99 
+12
source

You cannot edit the nth element of the list, the values ​​are immutable. You need to create a new list. But due to the immutability, it can share the part after the changed item with the original list.

So, if you want to apply the transformation to the nth element of the list (and have parts before and after identical), you have three parts

  • before the list before the item in question, say front
  • the element in question, say element
  • end of the list after the item in question, say back .

Then you assembled the pieces

 front ++ transform element : back 

so all that remained was to grasp at the interesting parts in a beautiful way.

 splitAt :: Int -> [a] -> ([a],[a]) 

does this, splitAt idx list returns the first part of the list before the idx index becomes the first component of the pair and the rest the second, so

 changeNthElement :: Int -> (a -> a) -> [a] -> [a] changeNthElement idx transform list | idx < 0 = list | otherwise = case spliAt idx list of (front, element:back) -> front ++ transform element : back _ -> list -- if the list doesn't have an element at index idx 

(Note: I started counting elements at 0, if you want to start counting at 1, you need to configure and use idx-1 .)

+7
source

All Articles