When I have the value go first and index come second in the argument list. The following code works
let rec replace value index list =
match index, list with
| 0, x::xs -> value::xs
| index, x::xs -> x::replace value (index - 1) xs
| index, [] -> failwith "index out of range"
let replaceCharArray = replace 'd' 1 ['a';'b';'c']
printfn "%A" replaceCharArray
let reversed_list = replace 100 2 [10;2;35;43;57]
printfn "%A" reversed_list
However, as soon as I swap value and index in the argument list my code breaks. I even have my arguments swapped so the index comes first and the replacement value comes after when I call the function, to prevent any issues, but I am still having issues.
let rec replace index value list =
match index, list with
| 0, x::xs -> value::xs
| index, x::xs -> x::replace value (index - 1) xs
| index, [] -> failwith "index out of range"
let replacedCharArray = replace 1 'd' ['a';'b';'c']
printfn "%A" replacedCharArray
let replacedNumList = replace 2 100 [10;2;35;43;57]
printfn "%A" replacedNumList
Could someone please help me figure this out?
The problem is that you didn't swap the parameters where you recurse. Change line 4 to:
| index, x::xs -> x :: replace (index - 1) value xs
Related
I have a sequence of Result and I would like to accumulate all the Error values yet abort processing and return the first Ok value found. Specifically, I would like to abort processing the remainder of the list. Unfortunately, the approach I have preserves the first Ok found but does not abort processing the rest of the list.
let process : Result<'t, string list> -> Result<'t, string list> =
let st0 = Error []
let acc st e =
match st, e with
| Ok _ , _ -> st
| _ , Ok _ -> e
| Error v, Error vs -> Error (v ++ vs)
Seq.scan acc st0
|> Seq.last
Ideally, a Seq.skipToOrDefault and Seq.takeToOrDefault methods would be nice to have for this.
From your comments, it has become clear that what you'd like to do is to avoid iterating over the whole sequence, stopping once you encounter the first Ok.
Well, sequences already do that by default (they're lazy), and the scan function preserves that property. Let's check:
let mySeq = seq {
for i in 0..3 do
printfn "Returning %d" i
yield i
}
mySeq |> Seq.toList |> ignore
> Returning 0
> Returning 1
> Returning 2
> Returning 3
mySeq |> Seq.take 2 |> Seq.toList |> ignore
> Returning 0
> Returning 1
mySeq
|> Seq.scan (fun _ x -> printfn "Scanning %d" x) ()
|> Seq.take 3
|> Seq.toList |> ignore
> Returning 0
> Scanning 0
> Returning 1
> Scanning 1
Look: we never see "Returning 2" and "Returning 3" after the scan. That's because we're not iterating over the whole sequence, only the piece we need, as determined by Seq.take 3.
But the thing that does force the full iteration in your code is Seq.last. After all, in order to get the last element, you need to iterate over the whole sequence, there is no other way.
But what you can do is stop iteration when you need via Seq.takeWhile. This function takes a predicate and returns only the elements for which the predicate is true, excluding the first one that yields false:
mySeq |> Seq.takeWhile (fun x -> x < 2) |> Seq.toList |> ignore
> Returning 0
> Returning 1
> Returning 2
> val it : int list = [0; 1]
The difficulty in your case is that you also need to return the element that breaks the predicate. In order to do that, you can deploy a little hack: keep around in your folding state a special flag stop: bool, initially set it to false, and switch to true on the element immediately succeeding the one where you need to stop. To keep such state, I am going to use a record:
let st0 = {| prev = Error []; stop = false |}
let acc (s: {| prev: Result<_,string>; stop: bool |}) x =
match s.prev, x with
| Ok _, _ -> {| s with stop = true |} // Previous result was Ok => stop now
| _, Ok _ -> {| s with prev = x |} // Don't stop, but remember the previous result
| Error a, Error b -> {| s with prev = Error (a # b) |}
sourceSequence
|> Seq.scan acc st0
|> Seq.takeWhile (fun s -> not s.stop)
|> Seq.last
|> (fun s -> s.prev)
P.S. also note that in F# list concatenation is #, not ++. Are you coming from Haskell?
I think this is a better solution. However, there is some confusion as to whether Seq.tryPick is always side effect free regardless of the underlying sequence. For list it is such that Seq.tail is required here to advance through it...
let rec scanTo (pred:'u -> bool) (acc:'u -> 'a -> 'u) (st0:'u) (ss:'a seq) = seq {
let q =
ss
|> Seq.tryPick Some
|> Option.bind (acc st0 >> Some)
match q with
| None -> yield! Seq.empty
| Some v when pred v -> yield v
| Some v -> yield v; yield! (scanTo pred acc v (Seq.tail ss))
}
For instance...
let process : Result<'v, string list> seq -> Result<'v, string list> seq = fun aa ->
let mergeErrors acc e =
match acc, e with
| Error ms, Error m -> Error (m # ms)
| _, Ok v -> Ok v
| _, Error m -> Error m
let st0 = Error []
let isOk = function
| Ok _ -> true
| _ -> false
scanTo isOk mergeErrors st0 aa
The thing is simple i think, the problem is:
With a given int list as example [25;30;45;60] return a int list with values [25;30+25;45+30+25;60+45+30+25].
I have 2 versions of the code (no one works).
let accu_weather lst =
let rec aux acc lst2 = function
| [] -> []
| h::t -> aux((acc+h) lst2::(h+acc)) lst
in 0 []
let accu_weather lst =
let rec accu lst2 = function
| [] -> []
| [x] -> x
| h::t -> (h+accu(t))::lst2
in accu List.rev(lst)
Someone knows the solution, and what im doing wrong??
Thanks!!
You wrote,
let accu_weather lst =
let rec aux acc lst2 = function
| [] -> []
| h::t -> aux((acc+h) lst2::(h+acc)) lst
in 0 []
First, here
in 0 []
You're applying 0 to an empty list. That doesn't make sense. There you should be making some call to your auxiliary function with the right arguments.
And here,
| h::t -> aux((acc+h) lst2::(h+acc)) lst
You are applying aux to ((acc+h) lst2::(h+acc)) and lst. What is the type of your first argument? and what is lst?
I'd suggest you start with a simpler exercise first. Such as just calculating the sum of the elements of the list (using an accumulator).
Try this:
let rec accu list =
match list with
|[] -> []
|l::[] -> [l]
|l::l1::r -> l::accu ((l1+l)::r);;
The following code works to replace the first element of the array,
but I would like to specify a value of 1 instead of a value of 0 to
delete the first element of the array.
let rec replace index value list =
match index, list with
| 0, x::xs -> value::xs
| index, x::xs -> x::replace (index - 1) value xs
| index, [] -> failwith "index out of range"
let replaceCharArray = replace 0 'd' ['a';'b';'c']
printfn "%A" replaceCharArray
I modified my code working code above so that I may do that, but now I
am getting an out of range exception.
let rec replace index value list =
match index, list with
| 0, x::xs -> value::xs
| index, x::xs -> x::replace ((index - 1) - 1) value xs
| index, [] -> failwith "index out of range"
let replaceCharArray = replace 1 'd' ['a';'b';'c']
printfn "%A" replaceCharArray
Can someone please help me figure out why I am getting an out of range
exception?
let rec replace index value list =
match index, list with
| 0, _ -> failwith "index out of range"
| 1, x::xs -> value::xs
| index, x::xs -> x::replace (index - 1) value xs
| index, [] -> failwith "index out of range"
I want to return true if I find a repeating value in the list
let rec repeats L =
match L with
| [] -> false
| x::xs when x = xs.Head -> true
| x::xs -> repeats xs;;
repeats [1;2;3;4;5]
Should return false. But I get this error:
System.InvalidOperationException: The input list was empty.
at Microsoft.FSharp.Collections.FSharpList`1.get_Head()
at FSI_0003.repeats[a](FSharpList`1 L)
at <StartupCode$FSI_0004>.$FSI_0004.main#()
at main#dm()
Stopped due to error
What should I do to fix the error?
The problem is that
x::xs = 5::[]
in the last case
You want to change it to
|x::xs::xss when x=xs -> true
I am trying to input a list into the function and it send me a list with the first half of the elements taken away using f# with the below recursion but I keep running into a base case problem that I just cant figure out. any thoughts? I am using the second shadow list to count how far I need to go until I am half way into the list (by removing two elements at a time)
let rec dropHalf listToDrop shadowList =
match shadowList with
| [] -> listToDrop
| shadowHead2::shadowHead1::shadowTail -> if shadowTail.Length<=1 then listToDrop else
match listToDrop with
|[] -> listToDrop
|listToDropHead::listToDropTail -> dropHalf listToDropTail shadowTail
let rec dropHalf listToDrop shadowList =
match shadowList with
| [] -> listToDrop
| shadowHead2::[] -> listToDrop (* odd number! *)
| shadowHead1::shadowHead2::shadowTail ->
match listToDrop with
| [] -> listToDrop (* should never happen? *)
| listToDropHead::listToDropTail -> dropHalf listToDropTail shadowTail
i'm afraid i don't use F#, but it's similar to ocaml, so hopefully the following is close to what you're looking for (maybe the comment format has changed?!). the idea is that when you exhaust the shadow you're done. your code was almost there, but the test for length on the shadow tail made no sense.
i want to emphasize that this isn't anything like anyone would write "in real life", but it sounds like you're battling with some weird requirements.
Because you use the shadow list with the same length as the original list and remove elements from these lists with different rates, it's better to create an auxiliary function:
let dropHalf xs =
let rec dropHalf' ys zs =
match ys, zs with
| _::_::ys', _::zs' -> dropHalf' ys' zs'
| _, zs' -> zs' (* One half of the shadow list ys *)
dropHalf' xs xs
If you don't care to traverse the list twice, the following solution is simpler:
let rec drop n xs =
match xs, n with
| _ when n < 0 -> failwith "n should be greater or equals to 0"
| [], _ -> []
| _, 0 -> xs
| _::xs', _ -> drop (n-1) xs'
let dropHalf xs =
xs |> drop (List.length xs/2)
and another simple solution needs some extra space but doesn't have to use recursion:
let dropHalf xs =
let xa = Array.ofList xs
xa.[xa.Length/2..] |> List.ofArray
As a general rule of thumb, if you're calling Length on a list, then there is most likely a better way to do what you're doing. Length has to iterate the entire list and is therefore O(n).
let secondHalf list =
let rec half (result : 'a list) = function
| a::b::sx -> half result.Tail sx
// uncomment to remove odd value from second half
// | (a::sx) -> result.Tail
| _ -> result
half list list
Here is a sample does what you described.
open System
open System.Collections.Generic
let items = seq { 1 .. 100 } |> Seq.toList
let getBackOfList ( targetList : int list) =
if (targetList.Length = 0) then
targetList
else
let len = targetList.Length
let halfLen = len / 2
targetList |> Seq.skip halfLen |> Seq.toList
let shortList = items |> getBackOfList
("Len: {0}", shortList.Length) |> Console.WriteLine
let result = Console.ReadLine()
Hope this helps