早上好, 首先我展示自己:我的名字是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有什么想法吗?
马蒂亚
答案 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.iter
或List.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