Reputation: 2140
In F# I need to get a list from an existing list with the value at a particular index changed from the original. All I can find on google and here relates to changing something based on value rather than index (fair enough, because lists don't really have a concept of "index", but I bet everyone knew what I meant).
This is obviously easy enough to code. At the moment I have:
// Replace element at index with newElement in seq. Does nothing if index is outside seq.
let updateElement index newElement seq =
let rec updateElementHelper seq count result =
match seq with
| [] -> result |> List.rev
| head::tail ->
if count = index then
updateElementHelper [] (count + 1) (newElement::result)@tail
else
updateElementHelper tail (count + 1) (head::result)
updateElementHelper seq 0 []
which seems to work just fine, but is there a more native way than this?
(F# newbie - or rather, returing after a very long break and never having got all that far the first time around).
Upvotes: 0
Views: 708
Reputation: 243096
The easiest way to implement this is probably to use the List.mapi
function - it calls a function you provide for each element of the list and gives you an index, so you can either return the original element or your new element, depending on the index:
let updateElement index element list =
list |> List.mapi (fun i v -> if i = index then element else v)
updateElement 4 40 [ 0 .. 9 ]
As noted by @Jarak, if you need to do this often, then it might be worth thinking whether there is some other more functional approach to your problem where you do not rely on indices - doing something like this would not be very typical thing to do in functional code.
Upvotes: 2
Reputation: 982
I am assuming that you don't want to allow the list to be mutable. If you did, then you could just index into the list and update the value, e.g. mylist.[index] <- newValue
.
I will say right now that any operation on a list that uses any other sort of access than the typical "head + tail -> recurse on tail" style is a strong sign that a list isn't the right data structure for your operation. See e.g. Juliet's answer here. Typically, if you want to be operating on a linear data structure by index, an array is your best bet.
The easiest way I can think of to do this if you still want to do it with a list, would be something like the following:
let newList = oldList.[..index - 1] @ (newValue :: oldList.[index + 1..])
(I might possibly have the indices slightly off)
This will probably have very poor performance, however. I think it would be reasonably fair to say that many F#-ers would call any use of @
or List slicing a code smell. As a very infrequent operation on small lists it might be alright, but if it will be used frequently, or on large lists, then it would be a good time to start thinking if a list is really the right collection data structure for your task.
Upvotes: 2