Преобразование кода C # в код F #: манипулирование списками - PullRequest
0 голосов
/ 29 августа 2011

Доброе утро, сначала я представляю себя: меня зовут Маттиа, я учусь в области компьютерных наук.

У меня проблема с тремя функциями, которые я уже реализовал в двух другихязык программирования (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
    

Спасибо, Маттиа.

Решения:

  • 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

Проблема в том, что мне нужно изменить три списка, и в рекурсивном стиле это невозможно, у кого-нибудь есть идеи?

Mattia

Ответы [ 3 ]

2 голосов
/ 29 августа 2011

Если вы изучаете 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 (добавляет значение в начало).Это может быть проблемой, если вы обрабатываете длинные списки, но вам, вероятно, сейчас не нужно беспокоиться.

Для получения дополнительной информации и некоторого введения в работу с функциональными списками, см. Этот MSDNстатья .

0 голосов
/ 31 августа 2011

Ваша первая функция просто перебирает список, копируя его и выполняя некоторые побочные эффекты для объектов в нем.Нет смысла копировать списки F #, потому что они неизменны, поэтому идиоматический перевод:

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

Вы также можете использовать Seq.iter или List.iter или вручную свернуть рекурсивный цикл, такой как в List.iter.

Хотя циклы эквивалентны рекурсивным функциям, которые выполняют тело и выполняют рекурсию, когда предикат удовлетворен:

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
0 голосов
/ 29 августа 2011

Ниже вы можете сделать следующее:

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

Подумайте о функции высшего порядка, прежде чем думать итеративно или рекурсивно

...