2017-08-11 175 views
0

我在我的一個需求中實現了遞歸。我的實際需求如下: -如何從遞歸遞歸函數

有一個主表名爲庫存,它有許多記錄,比如說「庫存A」,「庫存B」,「庫存C」。

還有一個表叫做庫存包它鏈接一個庫存與其他。所以庫存包表具有兩列: - 代表源庫存Id和目標庫存ID的TI & TI。

Record Ex。

SI TI

A B

B C

在,如果我點擊任何庫存,則關聯的庫存也應取了我的要求。

像這裏一樣,如果我點擊B然後A & C應該被取出。我使用以下遞歸方法來獲得要求: -

List<Guid> vmAllBundle = new List<Guid>(); 
List<Guid> vmRecursiveBundle = new List<Guid>(); 
List<Guid> processedList = new List<Guid>(); 

public List<Guid> GetAllRecursiveBundle(Guid invId, Guid originalInvId) 
     {      
      List<Guid> vmInvSrcBundleList = GetSourceInventory(invId); //Fetch to get All Related Source Inventories 
      List<Guid> vmInvTarBundleList = GetTargetInventory(invId); //Fetch to get All Related Target Inventories 

      vmAllBundle.AddRange(vmInvSrcBundleList); 
      vmAllBundle.AddRange(vmInvTarBundleList);   

      if (vmAllBundle.Contains(originalInvId)) 
       vmAllBundle.Remove(originalInvId); 
      vmAllBundle = vmAllBundle.Distinct().ToList(); 

      vmRecursiveBundle = vmAllBundle.ToList().Except(processedList).ToList(); 

      foreach (Guid vmInvBundle in vmRecursiveBundle) 
      { 
       vmRecursiveBundle.Remove(vmInvBundle); 
       processedList.Add(vmInvBundle); 
       GetAllRecursiveBundle(vmInvBundle, originalInvId); 

       if (vmRecursiveBundle.Count == 0) 
        return vmAllBundle; 
      } 

      return null; 
     } 

我能夠使用此方法獲取數據,但我在返回時遇到問題。

當我返回時,它調用GetAllRecursiveBundle()並使用foreach循環並繼續調用,直到vmAllBundle中的所有項都完成爲止。之後它退出遞歸。

這是我的新東西,所以張貼問題,問這是正常行爲還是一些代碼邏輯必須改變。

修改代碼

public List<Guid> GetAllRecursiveBundle(Guid invId, Guid originalInvId) 
     { 
      if (vmRecursiveBundle.Count > 0) 
       vmRecursiveBundle.Remove(invId); 

      List<Guid> vmInvSrcBundleList = GetSourceInventory(invId); //Fetch to get All Related Source Inventories 
      List<Guid> vmInvTarBundleList = GetTargetInventory(invId); //Fetch to get All Related Target Inventories 

      vmAllBundle.AddRange(vmInvSrcBundleList); 
      vmAllBundle.AddRange(vmInvTarBundleList);   

      if (vmAllBundle.Contains(originalInvId)) 
       vmAllBundle.Remove(originalInvId); 
      vmAllBundle = vmAllBundle.Distinct().ToList(); 

      vmRecursiveBundle = vmAllBundle.ToList().Except(processedList).ToList(); 

      foreach (Guid vmInvBundle in vmRecursiveBundle) 
      {     
       processedList.Add(vmInvBundle); 
       GetAllRecursiveBundle(vmInvBundle, originalInvId); 

       if (vmRecursiveBundle.Count == 0) 
        break; 
      } 

      return vmAllBundle; 
     } 
+0

是代碼無限期運行?它永遠不會結束嗎? –

+0

嗨德文,即使最初也沒有無限的時間。我修改了代碼。 – user1843970

+0

是否必須在遞歸方法內完成從表中獲取數據?我認爲如果遞歸方法只接受選定的清單及其之間的關係,那麼遞歸方法實現起來會簡單得多。 – Poosh

回答

1

通常情況下,遞歸方法調用需要像中斷值,這對回報進行檢查,對信號遞歸調用結束和停止調用reursive方法。我不完全瞭解你的代碼,因此這裏是一個例子:

private string SearchFileRecursive(string directory, string fileToFind) 
{ 
    string filePath = null; 

    string[] files = Directory.GetFiles(directory); 

    string foundFile = files.FirstOrDefault(file => (0 == string.Compare(Path.GetFileName(file), fileToFind, true))); 

    if(string.IsNullOrEmpty(foundFile)) 
    { // not found 
    string[] subDirectories = Directory.GetDirectories(directory); 
    foreach(string subDirectory in subDirectories) 
    { 
     filePath = SearchFileRecursive(subDirectory, fileToFind); 
     if(!string.IsNullOrEmpty(filePath)) // found 
     break; 
    } 
    } 
    else 
    { // found 
    filePath = Path.Combine(directory, foundFile); 
    } 

    return filePath; 
} 
+0

HI KBO,我修改了代碼。請看一下。在foreach循環中添加break不起作用。在foreach循環中的GetAllRecursiveBundle()會根據vmAllBundle List中的項目數在最終退出前被調用。對此有何想法? – user1843970

1

我非常驚訝你的代碼可以運行。

您正在修改正在迭代的列表foreach - 通常會引發異常。

foreach (Guid vmInvBundle in vmRecursiveBundle) 
{ 
    vmRecursiveBundle.Remove(vmInvBundle); // **CRASHES HERE** 
} 

修改收集由foreach正在迭代是不允許的,並會被認爲即使它被允許的(因爲它經常導致錯誤)不好的做法。

你可以改變一個for循環,有沒有這樣的顧慮:

for (int i = 0; i < vmRecursiveBundle.Count; i++) 
{ 
    Guid vmInvBundle = vmRecursiveBundle[i]; 

    vmRecursiveBundle.Remove(vmInvBundle); // **NO CRASH** 

    i--;  // counteracts the i++ so the next Guid is not skipped 
} 

有關進一步詳情,請參閱What is the best way to modify a list in a 'foreach' loop?

+0

嗨buffjape。感謝您分享最佳做法。我在Foreach Loop外面拿走了移除部分。請查看修改後的代碼,並告訴我是否可以。如果你可以在退出函數之前回答多次在foreach循環中調用GetAllRecursiveBundle()的查詢,那麼它會很好。我已經看到,在foreach循環中的GetAllRecursiveBundle()在最終退出前基於vmAllBundle List中的項目數被調用。 – user1843970

+0

我可以建議你運行代碼,看看它是否適合你。 – buffjape

+0

它正在爲我工​​作,但請讓我知道從編碼的角度來看它是否正確。 – user1843970