在某種程度上,遞回實作對我來說是一個令人困惑的主題。我想學習如何將正常方法準確地“翻譯”為遞回方法,經過一些研究,我仍然有些困惑,尤其是在第一步(遞回停止的地方)。
這個任務是左右旋轉一個陣列:
[TestCase(new[] { 1, 2 }, new[] { Direction.Left, Direction.Left, Direction.Right }, ExpectedResult = new[] { 2, 1 })]
我不想使用linq這個,我們可以使用Array.Copyandindices代替我的標準方法。
所以這是我要翻譯的代碼:
public static int[] Shift(int[] source, Direction[] directions)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
if (directions is null)
{
throw new ArgumentNullException(nameof(directions));
}
if (directions.Length == 0)
{
return source;
}
else
{
for (int i = 0; i < directions.Length; i )
{
switch (directions[i])
{
case Direction.Left:
var temp1 = source[0];
for (var j = 0; j < source.Length - 1; j )
{
source[j] = source[j 1];
}
source[source.Length - 1] = temp1;
break;
case Direction.Right:
var temp2 = source[source.Length - 1];
for (int j = source.Length - 1; j > 0; j--)
{
source[j] = source[j - 1];
}
source[0] = temp2;
break;
default:
throw new InvalidOperationException($"Incorrect {directions[i]} enum value.");
}
}
return source;
}
}
這是我在單獨的程式嘗試遞回上的小代碼:
public static int[] Shift(int[] source, Direction[] directions)
{
if (source is null || directions is null)
{
throw new ArgumentNullException(nameof(source));
}
ShiftRecursively(source, source.Length, directions, directions.Length);
}
public static int ShiftRecursively(int[] sourceShift, int n, Direction[] currentDirection, int iterations)
{
if (iterations == 0)
{
}
if (currentDirection == Direction.Left)
{
// Handle "left" shift.
}
else if (currentDirection == Direction.Right)
{
// Handle "right" shift.
}
else
{
throw new InvalidOperationException($"Incorrect {currentDirection} enum value.");
}
}
uj5u.com熱心網友回復:
免責宣告:我已經在評論中確定,我不認為這是一個“好”的例子,說明使用遞回實際上是一件明智的事情。所以,我不會關注那個或其他細節。只是純粹的“如何進行遞回”。
讓我們開始你的方法:
public static int ShiftRecursively(int[] sourceShift, int n, Direction[] currentDirection, int iterations)
{
// "n" is superfluent, here.
// I guess you are trying to model a stop-condition here?
if (iterations == 0)
{
}
// this is ok vv
if (currentDirection == Direction.Left)
{
// Handle "left" shift.
}
else if (currentDirection == Direction.Right)
{
// Handle "right" shift.
}
else
{
throw new InvalidOperationException($"Incorrect {currentDirection} enum value.");
}
// Now what's missing is the next layer of recursion ...
}
現在,我想把它改成:
public static int[] ShiftRecursively(int[] sourceShift, Direction[] directions, int iteration = 0)
{
// Stopping condition
if( iteration == directions.Length ) return sourceShift;
// iteration shall be increased in each recursion step,
// so we need to check if there are steps left to take.
// If not: Stop recursion = just return input.
// Data mutation
Direction currentDirection = directions[iteration];
// => factored out the application of 1 shift operation.
// Makes your code "cleaner".
int[] resultShift = Shift(sourceShift, currentDirection);
// Next layer of recursion
return ShiftRecursively(resultShift, directions, iteration 1);
}
開始通話: int[] result = ShiftRecursively(source, directions);
請注意,這只是一種可能的遞回場景。基本上我們可以區分何時觸發下一步與何時應用當前突變。這意味著:
- 您可以應用當前的變異并將該結果用作下一個遞回步驟的輸入。
- 或者您可以將輸入傳遞給下一個遞回步驟并改變結果。
- 或者你甚至可以兩者都做。
選擇哪一個取決于應用程式。
uj5u.com熱心網友回復:
讓我們從一般情況 開始:shift左(正)或右(負):
public static T[] MakeShift<T>(T[] source, int shift) {
if (source is null)
throw new ArgumentNullException(nameof(source));
if (source.Length == 0)
return Array.Empty<T>();
// A pinch of modular arithmetics:
// - negative shifts are converted into Length Shift
// - on large shifts (|Shift| > Length) we take remainder
shift = (shift % source.Length source.Length) % source.Length;
T[] result = new T[source.Length];
Array.Copy(source, shift, result, 0, source.Length - shift);
Array.Copy(source, 0, result, source.Length - shift, shift);
return result;
}
然后我們準備實施您的簽名:
public static int[] Shift(int[] source, Direction[] directions) {
if (source is null)
throw new ArgumentNullException(nameof(source));
if (directions is null)
throw new ArgumentNullException(nameof(directions));
int moves = 0;
// No Linq .Sum(), just a loop as we want
foreach (var dir in directions)
moves = (dir == Direction.Left ? 1 : -1);
return MakeShift(source, moves);
}
如果您堅持遞回解決方案,這對問題效率不高:
private static int[] ShiftRecursively(int[] source, Direction[] directions, int index) {
if (index < 0 || index >= directions.Length)
return source;
return ShiftRecursively(MakeShift(
source,
directions[index] == Direction.Left ? 1 : -1,
directions,
index 1));
}
public static int[] ShiftRecursively(int[] source, Direction[] directions) {
if (source is null)
throw new ArgumentNullException(nameof(source));
if (directions is null)
throw new ArgumentNullException(nameof(directions));
return ShiftRecursively(source, directions, 0);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/315941.html
