将C#代码转换为F#代码:列出操作

时间:2011-08-29 08:40:08

标签: list f# c#-to-f#

早上好, 首先我展示自己:我的名字是Mattia,我是计算机科学专业的学生。

我遇到了三个函数的问题,我已经在其他两种编程语言(C#和Python)中实现了,使用for和while这样的命令式循环,但我要做的是在递归中转换它们风格。

C#中的函数是:

  • resetList:给定两个列表,该方法初始化第一个列表对象内的计数器,并将新对象放在第二个列表中。

    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:给定要生成的整数(n),该方法返回一个列表,其中n随机整数选择在1到56之间。

    int i = 0;
    while (i < n)
    {
        int randomNumber = randomizer.Next(1, 56 + 1);
    
        if (!listOut.Contains(randomNumber))
        {
            listOut[I] = randomNumber;
            i++;
        }
    }
    
  • compareRule:给定两个自定义对象,该方法找到它们之间的第一个相等字符。

    int index = myObject1.Index;
    char myChar = myObject1.getChar();
    
    while ((index < 6) && !(myObject2.getChar().Equals(myChar)))
    {
        index++;
        myChar= myObject1.getCharAt(index);
    }
    
    myObject1.Counter++;
    

我可以用命令式循环方式转换它们,但不能以递归方式转换它们,例如:

  • 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
    

谢谢你,Mattia。

解决方案:

  • 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
    

更新:现在我正在处理这个(最后)while循环,我正试图以递归形式翻译。

(... 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]

(......一个不起作用的解决方案......)

(... 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

问题是我需要修改三个列表并且在递归样式中这是不可能的,sombody有什么想法吗?

马蒂亚

3 个答案:

答案 0 :(得分:2)

如果您正在学习F#,那么首先自己编写一些递归函数会很有用。稍后,您将了解到其中许多模式与某些现有模式匹配,您将使用List.map等函数(如Ankur的解决方案中所述)。

因此,要递归编写resetList函数,您可以这样做:

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)

这个实现不是 tail-recursive ,这意味着它在递归调用restList之后做了一些事情(它将值附加到前面)。如果您正在处理长列表,这可能是一个问题,但您现在可能不需要担心。

了解更多信息&amp; working with functional lists, see this MSDN article的一些介绍。

答案 1 :(得分:0)

以下是您可以做的事情:

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

在迭代或递归思考之前考虑更高阶函数

答案 2 :(得分:0)

你的第一个函数只是迭代一个列表,复制它并对其中的对象执行一些副作用。复制F#列表没有意义,因为它们是不可变的,因此惯用语翻译是:

let resetList inList flag =
  for o in inList do
    o.FirstCounter <- 0
    if flag then
      o.SecondCounter <- 0
  inList

您也可以使用Seq.iterList.iter或手动滚动List.iter中的递归循环。

while循环等同于执行正文的递归函数,并在满足谓词时递归:

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)

下一个while循环相同:

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