Convert C# code to F# code: lists manipulation
Good morning at all, first I present myself: my name is Mattia and I'm a student in Computer Science.
I've a problem with three function that I've already implement in two other programming language (C# and Python), using imperative loop like for and while, but what I've to do is to convert them in the recursive style.
The function in C# are:
resetList: given two list, the method initialize the counters inside the object of first list, and put the new object in the second list.
public static List<myObject> resetList(List<myObject> inList, List<myObject> outList, bool flag) { foreach (myObject myObj in inList) { myObj.FirstCounter= 0; if (flag) myObj.SecondCounter= 0; outList.Add(myObj ); } return outList; }
randomIntList: given the number of integer to generate (n), the method return a list with n random integer choosen between 1 and 56.
int i = 0; while (i < n) { int randomNumber = randomizer.Next(1, 56 + 1); if (!listOut.Contains(randomNumber)) { listOut[I] = randomNumber; i++; } }
compareRule: given two custom object, the method find the first equal character between them.
int index = myObject1.Index; char myChar = myObject1.getChar(); while ((index < 6) && !(myObject2.getChar().Equals(myChar))) { index++; myChar= myObject1.getCharAt(index); } myObject1.Counter++;
I can convert them in imperative loop style but not in recursive style, for example:
resetList:
(Imperative version) let resetList inList flag = let mutable outList = [] for myObj in inList do if flag = true then outList <- outList @ [new myObject(myObj.Index, 0, myObj.Chars, 0)] else outList <- outList @ [new myObject(myObj.Index, 0, myObj.Chars, myObj.Counter)] outList (Recursive version: try...) let resetList listaIn flag = let mutable outList = [] let rec resetListRec inList = match inList with | [] -> outList | head :: tail -> if flag = true then outList <- outList @ [new myObject(head.Index, 0, head.Chars, 0)] else outList <- outList @ [new myObject(head.Index, 0, head.Chars, head.Counter)] resetListRec tail
Thank you at all, Mattia.
Solutions:
resetList:
let rec resetList list flag = match list with | [] -> [] | (myObj : myObject) :: myObjs -> let myObj = if flag then new myObject(myObj.Index, 0, myObj.Chars, 0) else new myObject(myObj.Index, 0, myObj.Chars, myObjs.Counter) myObj :: (resetList myObjs flag)
findCharEqual:
let rec findCharEqual index (myObj1 : myObject) (myObj2 : myObject) = let char1 = myObj1.GetChar() let char2 = myObj1.GetChar(index) if (index < 6) && (char1 <> char2) then findCharEqual (index + 1) myObj1 myObj2 else new myObject(myObj2.Index, index, myObj2.Chars, myObj2.Counter + 1)
randomList:
let randomList n = let randomizer = new Random() Seq.initInfinite (fun _ -> randomizer.Next(1, MAX_N + 1)) |> Seq.distinct |> Seq.take n |> Seq.toList
Update: Now I'm working with this (last) while loop that I'm trying to translate in recursive form.
(... declaration of listIn, listOut, listTemp...)
while (listOut.Length < n) do
let mutable myObj1 = new myObject(0, 0, Array.empty, 0)
let mutable myObj2 = new myObject(0, 0, Array.empty,0)
if (listIn.Length = 0) then
if (listOut.Length > 1) then
myObj1 <- listOut.[listOut.Length - 2]
myObj2 <- new myObject(listOut.[listOut.Length - 1].Index, listOut.[listOut.Length - 1].Char + 1, listOut.[listOut.Length - 1].Chars, listOut.[listOut.Length - 1].Counter)
listOut <- removeObject (listOut.Length - 1) listOut
if (myObj2.Counter < 2) then
listIn <- listIn @ resetObject listTemp false
开发者_如何学编程 listTemp <- List.empty<myObject>
else
myObj1 <- new myObject(listOut.Head.Index, listOut.Head.Char + 1, listOut.Head.Chars, listOut.Head.Counter)
listOut <- List.empty<myObject>
listOut <- listOut @ [myObj1]
listIn <- listIn @ resetObject listTemp true
listTemp <- List.empty<myObject>
myObj2 <- listIn.Head
listIn <- removeObject 0 listIn
else
myObj1 <- listOut.[listOut.Length - 1]
myObj2 <- listIn.Head
listIn <- removeObject 0 listIn
let mutable indFxDx = myObj2.Char
myObj2 <- fingEqualChar indFxDx myObj1 myObj2
if (myObj2.Char < 6) then
if (myObj1.leftChar = myObj2.rightChar) then
listOut <- listOut @ [myObj2]
if (listTemp.Length > 0) then
listIn <- listIn @ resetObject listTemp false
listTemp <- List.empty<myObject>
else
listTemp <- listTemp @ [myObj2]
(... A not working solution ...)
(... declaration of listIn, listOut, listTemp...)
let rec findSolution i =
if i < n then
(... function atre the while declaration, to the end...)
findSolution (i + 1)
listOut <- findSolution 0
The problem is that I need to modify three lists and in the recursive style this is not possible, sombody have any idea?
Mattia
If you're learning F# then it is useful to first write a few recursive functions yourself. Later, you'll learn that many of them match some existing pattern and you'll use functions like List.map
(as in Ankur's solution).
So, to write your resetList
function recursively, you would do something like this:
let rec resetList inList flag =
match inList with
| [] -> [] // For empty list, we can only return emtpy list
| x::xs ->
// For non-empty list, create an object depending on the 'flag'
let obj =
if flag then new myObject(myObj.Index, 0, myObj.Chars, 0)
else new myObject(myObj.Index, 0, myObj.Chars, myObj.Counter)
// Process the rest of the list (recursively) and then add
// object we just created to the front
obj :: (resetList xs flag)
This implementation is not tail-recursive, which means that it does something after calling restList
recursively (it appends value to the front). This can be a problem if you're processing long lists, but you probably don't need to worry at the moment.
For more information & some introduction to working with functional lists, see this MSDN article.
Below is something that you can do:
let resetList inList outList flag =
outList @ inList |> List.map (fun i -> i.FirstCounter = 0;
match flag with
| true -> i.SecondCounter = 0; i
| _ -> i)
let randomList n =
let rnd = new Random()
seq {while true do yield rnd.Next(1,56)}
|> Seq.distinct
|> Seq.take n
|> Seq.toList
let findCharEqual obj1 obj2 =
let c = obj1.getChar()
let d = obj2.getChar()
if c = d then
c
else
findCharEqual obj1 obj2
Think about higher order function before thinking iteratively or recursively
Your first function just iterates over a list copying it and performing some side effects on the objects in it. There is no point in copying F# lists because they are immutable so the idiomatic translation is:
let resetList inList flag =
for o in inList do
o.FirstCounter <- 0
if flag then
o.SecondCounter <- 0
inList
You could also use Seq.iter
or List.iter
or hand-roll a recursive loop like the one in List.iter
.
While loops are equivalent to recursive functions that execute the body and recurse when the predicate is satisfied:
let rec loop i =
if i < n then
let randomNumber = randomizer.Next(1, 56 + 1)
if listOut.Contains randomNumber then
listOut.[i] <- randomNumber
loop (i + 1)
Same for the next while
loop:
let rec loop index myChar =
if index < 6 && not (myObject2.getChar().Equals myChar) then
myObject1.getCharAt index |> loop (index + 1)
myObject1.getChar() |> loop myObject1.Index
myObject1.Counter <- myObject1.Counter + 1
精彩评论