各位大神,
遇到这样一个问题,我有这样一个对象,
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层。