2012-09-03 34 views
2

我的程序工作,其中每个项目可容纳项目的数组(我正在做一个菜单,其中有一个树形结构)C#递归程序与列表

目前,我有项目作为列表,而不是一个数组,但我不觉得我正在充分利用它来简化代码。我在标准数组上选择了一个列表,因为接口(.add,.remove等等)很有意义。

我有代码来搜索结构并返回名称的路径(即Item.subitem.subsubitem.subsubsubitem)。以下是我的代码:

public class Item 
{ 
                   //public Item[] subitem; <-- Array of Items 
    public List<Item> subitem;         // <-- List of Items 

    public Color itemColor = Color.FromArgb(50,50,200); 
    public Rectangle itemSize = new Rectangle(0,0,64,64); 
    public Bitmap itemBitmap = null; 
    public string itemName; 


    public string LocateItem(string searchName) 
    { 
     string tItemName = null; 

     //if the item name matches the search parameter, send it up) 
     if (itemName == searchName) 
     { 
      return itemName; 
     } 

     if (subitem != null) 
     { 

      //spiral down a level 
      foreach (Item tSearchItem in subitem) 
      { 
       tItemName = tSearchItem.LocateItem(searchName); 

       if (tItemName != null) 
        break; //exit for if item was found 
      } 
     } 


     //do name logic (use index numbers) 
     //if LocateItem of the subitems returned nothing and the current item is not a match, return null (not found) 
     if (tItemName == null && itemName != searchName) 
     { 
      return null; 
     } 

     //if it's not the item being searched for and the search item was found, change the string and return it up 
     if (tItemName != null && itemName != searchName) 
     { 
      tItemName.Insert(0, itemName + "."); //insert the parent name on the left --> TopItem.SubItem.SubSubItem.SubSubSubItem 
      return tItemName; 
     } 

     //default not found 
     return null; 
    } 


} 

我的问题是,如果有一个更容易的方法来做到这一点与列表?我一直在脑海中回想我应该使用列表还是数组。我有一个列表的唯一原因是,我不必每次添加或删除项目时都要调整数组的大小。

回答

2

列出声音很大。尽管如此,我会建议你的定义有所变化。尝试创建类是这样的:

public class Item : List<Item> 
{ 
    public string Name; 
} 

如果从List<Item>Item继承您自动让一棵树,而无需subitem领域。

这里是我的类的完整版:

public class Item : List<Item> 
{ 
    public string Name; 

    private List<Item> LocateItems(string searchName) 
    { 
     if (this.Name == searchName) 
      return (new [] { this }).ToList(); 

     var result = 
      this 
       .Select(s => s.LocateItems(searchName)) 
       .Where(x => x !=null && x.Count > 0) 
       .FirstOrDefault(); 

     if (result != null) 
      result.Add(this); 

     return result; 
    } 

    public string LocateItem(string searchName) 
    { 
     var items = this.LocateItems(searchName); 
     if (items == null) 
      return null; 
     else 
      return String.Join(".", items.Select(i => i.Name).Reverse()); 
    } 
} 

LocateItems返回Item开始与Item匹配和后面所有的父Item实例直至并包括根列表的方法。

我这个代码进行测试:

var foos = new Item() { Name = "Foo" }; 
var bars = new Item() { Name = "Bar" }; 
var qazs = new Item() { Name = "Qaz" }; 
var wees = new Item() { Name = "Wee" }; 

foos.Add(bars); 
bars.Add(qazs); 
foos.Add(wees); 

Console.WriteLine(foos.LocateItem("Wee")); 
Console.WriteLine(foos.LocateItem("Qaz")); 
Console.WriteLine(foos.LocateItem("Bar")); 
Console.WriteLine(foos.LocateItem("Foo")); 

而且我得到了这些结果:

Foo.Wee 
Foo.Bar.Qaz 
Foo.Bar 
Foo 
+0

有几行我不熟悉的(我刚刚进入LINQ的东西) 。 FirstOrDefault是做什么的?另外,计数是多少?另外,我想确保我有这个直线,它将每个级别都添加到列表中,然后以相反的顺序加入最后的点。 最后,.Select .Where行像SQL数据库一样工作吗? –

+1

'FirstOrDefault'扩展方法返回序列中的第一个值,忽略其余部分,但如果序列不包含任何值,将返回'null'。它是这样说的:“给我第一个匹配的搜索,如果没有匹配,则为null”。我的答案中描述了LocateItems方法。因为列表中的第一项是叶节点,所以在加入之前必须将它们反转。 “Select”对所有子项和“Where”过滤器执行递归搜索,非常类似于数据库查询,但是在内存中。 – Enigmativity

+0

我采用了你的方法,因为我认为它更容易,但我对一件事很好奇。你说过.Select对所有子项执行递归搜索。使用我的原始代码,它是否会包括搜索'subitem'对象中的所有项目,还是不会因为它是直接包含在列表中的对象而不是子项目本身? –

2

在这种情况下使用列表是完全可以接受的。如果性能是一个问题,数组将会是一个更好的选择 - 如果是这样的话,数组会稍微快一些,但是您发现的灵活性要差得多。

有一件事人们没有谈论得够多,就是简单性是构造代码的重要基础。如果使用列表编写和维护数组比使用列表更简单,那么使用列表(所有其他都相同)是完全正确的。

1

我会建议列表。由于向数组添加/删除项目会重新分配内存,因此对于项目的动态集合(我认为这是您的情况),列表通常总体上具有更好的性能。你可能想看一看:

Array versus List<T>: When to use which?