当前位置: 代码迷 >> C# >> 在层级列表中怎么查找并删除指定对象
  详细解决方案

在层级列表中怎么查找并删除指定对象

热度:70   发布时间:2016-05-05 05:04:13.0
在层级列表中如何查找并删除指定对象
各位大神,

遇到这样一个问题,我有这样一个对象,
    public class Question
    {
        public List<Question> Questions { get; set; }

        public string Title { get; set; }

        public int Score { get; set; }
    }


在Question对象中会嵌套一个List<Question>对象。
这是我模拟的一个Question列表,

 List<Question> QuestionList = new List<Question>();

            Question Q11 = new Question()
            {
                Title = "1.1",
                Score = 5,
            };

            Question Q12 = new Question()
            {
                Title = "1.2",
                Score = 5,
            };

            Question Q13 = new Question()
            {
                Title = "1.3",
                Score = 5,
            };

            List<Question> Q13List = new List<Question>();

            Question Q131 = new Question()
            {
                Title = "1.3.1",
                Score = 5,
            };

            Question Q132 = new Question()
            {
                Title = "1.3.2",
                Score = 5,
            };

            List<Question> Q132List = new List<Question>();

            Question Q1321 = new Question()
            {
                Title = "1.3.2.1",
                Score = 5,
            };

            Question Q1322 = new Question()
            {
                Title = "1.3.2.2",
                Score = 5,
            };

            Question Q1323 = new Question()
            {
                Title = "1.3.2.3",
                Score = 5,
            };

            Q132.Questions = Q132List;

            Q13List.Add(Q131);
            Q13List.Add(Q132);

            Q13.Questions = Q13List;

            List<Question> Q1List = new List<Question>();
            Q1List.Add(Q11);
            Q1List.Add(Q12);
            Q1List.Add(Q13);

            Question Q1 = new Question()
            {
                Title = "First One",
                Score = 25,
                Questions = Q1List,
            };

            Question Q2 = new Question()
            {
                Title = "Second",
                Score = 25,
            };

            Question Q3 = new Question()
            {
                Title = "Third",
                Score = 25,
            };

            QuestionList.Add(Q1);
            QuestionList.Add(Q2);
            QuestionList.Add(Q3);


然后我需要找到这个列表中一个指定的Question对象,并从中删除它,这个Question可能是第一层的,也可能是第二层的,例如我要找到并删除,

            Question needDeleteQuestion = new Question()
            {
                Title = "1.3.2",
                Score = 5,
            };


我该怎么做呢?如何找到这个需要删除的Question。
------解决思路----------------------
给你写了一个demo
using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Question> QuestionList = new List<Question>();

            Question Q11 = new Question()
            {
                Title = "1.1",
                Score = 5,
            };

            Question Q12 = new Question()
            {
                Title = "1.2",
                Score = 5,
            };

            Question Q13 = new Question()
            {
                Title = "1.3",
                Score = 5,
            };

            List<Question> Q13List = new List<Question>();

            Question Q131 = new Question()
            {
                Title = "1.3.1",
                Score = 5,
            };

            Question Q132 = new Question()
            {
                Title = "1.3.2",
                Score = 5,
            };

            List<Question> Q132List = new List<Question>();

            Question Q1321 = new Question()
            {
                Title = "1.3.2.1",
                Score = 5,
            };

            Question Q1322 = new Question()
            {
                Title = "1.3.2.2",
                Score = 5,
            };

            Question Q1323 = new Question()
            {
                Title = "1.3.2.3",
                Score = 5,
            };

            Q132.Questions = Q132List;

            Q13List.Add(Q131);
            Q13List.Add(Q132);

            Q13.Questions = Q13List;

            List<Question> Q1List = new List<Question>();
            Q1List.Add(Q11);
            Q1List.Add(Q12);
            Q1List.Add(Q13);

            Question Q1 = new Question()
            {
                Title = "First One",
                Score = 25,
                Questions = Q1List,
            };

            Question Q2 = new Question()
            {
                Title = "Second",
                Score = 25,
            };

            Question Q3 = new Question()
            {
                Title = "Third",
                Score = 25,
            };

            QuestionList.Add(Q1);
            QuestionList.Add(Q2);
            QuestionList.Add(Q3);

            var all = GetAll(QuestionList);
            Console.WriteLine("现在总共有 {0} 个Question。", all.Count());

            var search = (from t in all
                          let q = t.Item1
                          where q.Title == "1.3.2" && q.Score == 5
                          select t).ToList();
            Console.WriteLine("找到{0}个符合条件的Question。", search.Count);

            if (search.Any(r => r.Item1.Questions != null && r.Item1.Questions.Count > 0))
                throw new Exception("Question的Questions集合不是空的,不能删除。");

            foreach (var r in search)
                r.Item2.Questions.Remove(r.Item1);      //从父Question的Questions属性中删除子Quenstion

            Console.WriteLine("总共有 {0} 个Question。", GetAll(QuestionList).Count());
            Console.WriteLine("_________________按任意键结束。");
            Console.ReadKey();
        }

        /// <summary>
        /// 返回所有的Question极其父Question。
        /// </summary>
        /// <param name="list">要遍历的树。</param>
        /// <returns>返回子Question及其父Question的 Tuple 结构列表。
        /// 对于顶级Question,则父Question为null。</returns>
        public static IEnumerable<Tuple<Question, Question>> GetAll(List<Question> list)
        {
            foreach (var r in GetAll(list, null))
                yield return r;
        }

        private static IEnumerable<Tuple<Question, Question>> GetAll(List<Question> list, Question parent)
        {
            foreach (var q in list)
            {
                yield return new Tuple<Question, Question>(q, parent);
                var children = q.Questions;
                if (children != null && children.Count > 0)
                    foreach (var r in GetAll(q.Questions, q))
                        yield return r;
            }
        }

    }

    public class Question
    {
        public List<Question> Questions { get; set; }

        public string Title { get; set; }

        public int Score { get; set; }
    }
}


要删除它,必须先找到它。而要找到它,就需要递归搜索。

在数据结构上,由于需要知道它的parent才能删除它,因此搜索的结果是得到 Tuple<Question,Question> 这样的“子-父”结构。

在搜索功能上,使用了c#的迭代器功能,方便于将搜索应用到各种灵活的枚举功能的场合。例如使用 Linq 中。
------解决思路----------------------
这里边有两个功能点:

首先是 GetAll 方法中,使用 5、6行代码对树进行深度优先搜索,并且以c#的迭代器模式输出出来。

第二点就是在数据结构上返回了“子Question与其父Question的元组”。当然你也可以自定义一个有着两个属性的class。关键是要知道返回“两个”属性才够进行后续删除动作。
------解决思路----------------------
实际开发中,需要反之无限递归的情况出现。(你可以设计一个测试用例,仅仅有2个Questiion,就能产生一个无限递归)

这个你自己修改吧。有多种形式。例如可以在递归查找(第二个Get方法)的参数上增加一个“已经查找出来的Question的收集集合,在 yield return 返回结果之前先判断一下是否重复。或者(更轻量的方式)是在这个方法参数上仅增加一个“递归深度”数值,并且程序判断最多仅递归5层。
  相关解决方案