【问题标题】:C# recursive programming with lists使用列表进行 C# 递归编程
【发布时间】:2012-09-03 03:06:35
【问题描述】:

我正在开发一个程序,其中每个项目都可以包含一组项目(我正在制作一个菜单,它具有树状结构)

目前我将项目作为列表而不是数组,但我觉得我没有充分利用它来简化代码。我选择了一个列表而不是标准数组,因为接口(.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;
    }


}

我的问题是,是否有更简单的方法来处理列表?关于应该使用列表还是只使用数组,我一直在脑海中反复思考。我有一个列表的唯一原因是我不必在每次添加或删除项目时编写代码来调整数组的大小。

【问题讨论】:

    标签: c# class recursive-datastructures


    【解决方案1】:

    列表听起来很棒。不过,我建议对您的定义进行一些修改。尝试像这样创建您的课程:

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

    如果您让Item 继承自List&lt;Item&gt;,您会自动将其设为树,而无需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
    

    【讨论】:

    • 有几行我不熟悉(我刚接触 LINQ 的东西)。 FirstOrDefault 做什么?另外,什么是 .Count 计数?另外,我想确保我有这个直线,它将每个级别添加到一个列表中,然后在末尾以相反的顺序加入点?最后,.Select .Where 行是否像 SQL 数据库一样工作?
    • FirstOrDefault 扩展方法返回序列中的第一个值,忽略其余值,但如果序列不包含任何值,将返回 null。在这种情况下,它是否说“给我搜索的第一个匹配项,如果没有匹配项,则为 null”。我的回答中描述了LocateItems 方法。因为列表中的第一项是叶节点,所以在加入之前必须将它们反转。 Select 对所有子项执行递归搜索,Where 过滤所有不匹配项 - 非常类似于数据库查询,但在内存中。
    • 我采用您的方法是因为我认为这似乎更容易,但我对一件事感到好奇。您说 .Select 对所有子项执行递归搜索。使用我的原始代码,它是否包括搜索“子项”对象中的所有项目,还是因为它是直接包含在列表中的对象,而不是子项本身?
    • 抱歉,我不确定你在问什么。你能更清楚地解释你的问题吗?
    • 例如,您使用 .select,您说它会进行递归搜索,我认为这意味着它可以执行“无限”个级别来找到匹配项。该示例还表明,您可以使用单个 LocateItem 找到“Wee”,即使它不在顶部列表中,而是在包含列表、包含列表等的列表中......但是,我的代码和我的代码是您的类继承自 List,而我的类在该类中创建了一个完整的单独列表对象。所以我的问题是“.Select”是否可以递归地使用我的原始代码
    【解决方案2】:

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

    人们谈论得不够多的一件事是,简单性是构建代码的重要基础。如果使用列表比数组更容易编写和维护,那么(在其他条件相同的情况下)使用列表是完全正确的。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-20
        • 1970-01-01
        • 2021-08-31
        • 2020-03-08
        • 2014-05-05
        • 1970-01-01
        • 2018-06-10
        • 2012-09-20
        相关资源
        最近更新 更多