开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜