c#递归泛型数据结构搜索
我已经为此挣扎了好几天了,但仍然感到困惑。 我有一个数据结构,它从可以容纳其他容器的容器开始,最后是叶节点。我正在寻找一种直接迭代类型元素的方法,而不将它们拉入另一个集合,这样我就可以在适当的位置对它们进行操作,然后保存生成的结构 下面的代码是一个noddy版本,如果您在每个findElements函数上设置一个断点,您将看到它在不递归的情况下退出。这是在mono和ms运行时上进行的,所以我肯定是我没有得到什么东西,而不是一个bug;) 此外,理想情况下,函数应为c#递归泛型数据结构搜索,c#,generics,recursion,C#,Generics,Recursion,我已经为此挣扎了好几天了,但仍然感到困惑。 我有一个数据结构,它从可以容纳其他容器的容器开始,最后是叶节点。我正在寻找一种直接迭代类型元素的方法,而不将它们拉入另一个集合,这样我就可以在适当的位置对它们进行操作,然后保存生成的结构 下面的代码是一个noddy版本,如果您在每个findElements函数上设置一个断点,您将看到它在不递归的情况下退出。这是在mono和ms运行时上进行的,所以我肯定是我没有得到什么东西,而不是一个bug;) 此外,理想情况下,函数应为 IEnumerable<
IEnumerable<object> findElements<T>();
最好是
if (this is T) yield return (T)this;
谢谢你的建议/清晰/轻松
using System;
using System.Collections.Generic;
using System.Text;
namespace covariantTest {
class MainClass {
public static void Main(string[] args) {
Console.WriteLine("Starting");
Document root = new Document("rooty");
root.Children.Add(new File("file 1"));
root.Children.Add(new File("file 2"));
Document doc2 = new Document("doc2");
File file3 = new File("file 3");
file3.Lines.Add(new Line("line 1 file 3"));
file3.Lines.Add(new Line("line 2 file 3"));
doc2.Children.Add(file3);
File file4 = new File("file 4");
file4.Lines.Add(new Line("stuff about stuff"));
file4.Lines.Add(new Line("Babylon n ting"));
file4.Lines.Add(new Line("last line"));
doc2.Children.Add(file4);
root.Children.Add(doc2);
// find the lines
foreach (object obj in root.findElements<Line>()) {
Line line = obj as Line;
Console.WriteLine(line.Contents);
}
// done
Console.WriteLine("Press enter to finish");
Console.ReadLine();
}
}// Main
#region classes
public class Line : ISearchable {
private string _contents = string.Empty;
public Line() {}
public Line(string contents) {
_contents = contents;
}
#region properties
public string Contents {
get { return _contents; }
set { _contents = value; }
}
#endregion properties
public IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
}
}// Line
public class File : Container {
private List<Line> _lines = new List<Line>();
public File() : base() {}
public File(string name) : base(name) {}
#region properties
public List<Line> Lines {
get { return _lines; }
set { _lines = value; }
}
#endregion properties
public override IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
else base.findElements<T>();
}
}// File
public class Document : Container {
public Document() : base() {}
public Document(string name) : base(name) {}
public override IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
else base.findElements<T>();
}
}// Document
public abstract class Container : ISearchable {
private string _name = string.Empty;
private List<Container> _children = new List<Container>();
public Container() {}
public Container(string name) {
_name = name;
}
#region properties
public string Name {
get { return _name; }
set { _name = value; }
}
public List<Container> Children {
get { return _children; }
set { _children = value; }
}
#endregion properties
#region interfaces
public virtual IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
foreach (Container item in _children) {
item.findElements<T>();
}
}
#endregion interfaces
}// Container
#endregion classes
#region interfaces
public interface ISearchable {
IEnumerable<object> findElements<T>();
}
#endregion interfaces
}// namespace
使用系统;
使用System.Collections.Generic;
使用系统文本;
命名空间协变项{
类主类{
公共静态void Main(字符串[]args){
控制台写入线(“启动”);
文档根=新文档(“根”);
添加(新文件(“文件1”);
添加(新文件(“文件2”);
文件doc2=新文件(“doc2”);
文件file3=新文件(“文件3”);
file3.Lines.Add(新行(“第1行文件3”);
添加(新行(“第2行文件3”);
doc2.Children.Add(文件3);
文件file4=新文件(“文件4”);
file4.Lines.Add(新行(“stuff about stuff”);
文件4.行。添加(新行(“巴比伦n庭”);
file4.Lines.Add(新行(“最后一行”);
doc2.Children.Add(文件4);
root.Children.Add(doc2);
//找出台词
foreach(root.findElements()中的对象obj){
直线=obj作为直线;
Console.WriteLine(行内容);
}
//完成
Console.WriteLine(“按enter键完成”);
Console.ReadLine();
}
}//主要
#区域类
公共类行:ISearchable{
私有字符串_contents=string.Empty;
公用线路(){}
公用行(字符串内容){
_内容=内容;
}
#区域属性
公共字符串内容{
获取{return\u contents;}
设置{u contents=value;}
}
#端域属性
公共IEnumerable findElements(){
如果(这是T)收益率,则返回该收益率;
}
}//线
公共类文件:容器{
私有列表_行=新列表();
公共文件():基(){}
公共文件(字符串名称):基(名称){}
#区域属性
公共列表行{
获取{返回_行;}
设置{u行=值;}
}
#端域属性
公共覆盖IEnumerable findElements(){
如果(这是T)收益率,则返回该收益率;
else base.findElements();
}
}//文件
公共类文档:容器{
公共文档():基(){}
公共文档(字符串名称):基(名称){}
公共覆盖IEnumerable findElements(){
如果(这是T)收益率,则返回该收益率;
else base.findElements();
}
}//文件
公共抽象类容器:ISearchable{
私有字符串_name=string.Empty;
私有列表_children=新列表();
公共容器(){}
公共容器(字符串名称){
_名称=名称;
}
#区域属性
公共字符串名称{
获取{return\u name;}
设置{u name=value;}
}
公开儿童名单{
获取{return\u children;}
设置{u children=value;}
}
#端域属性
#区域界面
公共虚拟IEnumerable findElements(){
如果(这是T)收益率,则返回该收益率;
foreach(子容器中的容器项目){
item.findElements();
}
}
#端域接口
}//容器
#端域类
#区域界面
公共接口是可实现的{
IEnumerable findElements();
}
#端域接口
}//名称空间
我认为您的代码有点复杂,但我可能不太理解您的目标。不管怎样,这里有一个样本,可以用“平面方式”扫描你的树。我还使用了一个非常小的代码来演示如何操作,但显然您必须继续操作。
namespace ConsoleApplication3
{
//this is a node of your tree, but you may add whatever you want inside
class Item
{
public List<Item> Items { get; set; }
}
class Program
{
static void Main(string[] args)
{
//define the tree structure
var tree = new Item();
// (complete your tree-structrure)
//define the action delegate
Action<Item> action = (item) => Console.WriteLine(item);
//scan the hierarchy
Scan(
tree,
typeof(Item),
action);
}
//here is the flat-scan function, the "typeToFind" here is just
//for example and have very little sense to be in
static void Scan(
Item startItem,
Type typeToFind,
Action<Item> action)
{
var temp = new List<Item>();
temp.Add(startItem);
while (temp.Count > 0)
{
var item = temp[0];
temp.RemoveAt(0);
if (typeToFind.IsInstanceOfType(item))
{
action(item);
}
temp.AddRange(item.Items);
}
}
}
}
命名空间控制台应用程序3
{
//这是树的一个节点,但您可以在其中添加任何需要的内容
类项目
{
公共列表项{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
//定义树结构
变量树=新项();
//(完成您的树结构)
//定义动作委托
动作动作=(项目)=>Console.WriteLine(项目);
//扫描层次结构
扫描(
树,
(项目)的类型,
行动);
}
//这是平面扫描功能,这里的“typeToFind”只是
//比如说,你没有什么意义
静态空洞扫描(
startItem项目,
键入typeToFind,
行动(行动)
{
var temp=新列表();
添加温度(startItem);
而(温度计数>0)
{
var项目=温度[0];
移除温度(0);
if(类型查找IsInstanceOfType(项目))
{
行动(项目);
}
临时添加范围(项目);
}
}
}
}
希望这有帮助。干杯。您希望它如何工作?如果我理解正确,那么当从另一个函数调用yield时,yield不起作用(因此,如果调用base.findElements,则不会从中得到任何结果)。我建议不让步地重写它。为了避免创建许多列表,我将以如下方式将列表作为参数传递:
public interface ISearchable {
void doFindElements<T>(List<T> putThemHere);
}
// this is extender for syntactical sugar
public static class SearchableExtender
{
public static IEnumerable<T> findElements<T>(this ISearchable obj)
{
List<T> result = new List<T>();
obj.doFindElements(result);
return result;
}
}
public abstract class Container : ISearchable {
...
public virtual void doFindElements<T>(List<T> putThemHere)
{
if (this is T) putThemHere.Add(this);
foreach (Container item in _children) { item.doFindElements(putThemHere); }
}
...
}
公共接口是可实现的{
作废doFindElements(在此处列出);
}
//这是合成糖的延长剂
公共静态类SearchableExtender
{
公共静态IEnumerable findElements(此ISearchable obj)
public interface ISearchable {
void doFindElements<T>(List<T> putThemHere);
}
// this is extender for syntactical sugar
public static class SearchableExtender
{
public static IEnumerable<T> findElements<T>(this ISearchable obj)
{
List<T> result = new List<T>();
obj.doFindElements(result);
return result;
}
}
public abstract class Container : ISearchable {
...
public virtual void doFindElements<T>(List<T> putThemHere)
{
if (this is T) putThemHere.Add(this);
foreach (Container item in _children) { item.doFindElements(putThemHere); }
}
...
}