C# 递归LINQ调用
我试图用父子关系构建一些数据的XML树,但是在同一个表中 这两个重要领域是: 竞争 家长竞争ID 有些数据可能是 CompetitionID=1, ParentCompetitionID=null 竞争ID=2, ParentCompetitionID=1 竞争ID=3, ParentCompetitionID=1 我使用的中断查询只是以平面格式显示结果。鉴于我正在使用XML,需要某种递归功能。我可以使用普通for循环递归来实现这一点,但我想看看linq版本。谢谢你的帮助C# 递归LINQ调用,c#,linq,C#,Linq,我试图用父子关系构建一些数据的XML树,但是在同一个表中 这两个重要领域是: 竞争 家长竞争ID 有些数据可能是 CompetitionID=1, ParentCompetitionID=null 竞争ID=2, ParentCompetitionID=1 竞争ID=3, ParentCompetitionID=1 我使用的中断查询只是以平面格式显示结果。鉴于我正在使用XML,需要某种递归功能。我可以使用普通for循环递归来实现这一点,但我想看看linq版本。谢谢你的帮助 var results
var results =
from c1 in comps
select new {
c.CompetitionID,
SubComps=
from sc in comps.Where (c2 => c2.CompetitionID == c1.CompetitionID)
select sc
};
更新
我发现了Chris Eargle的一篇有趣的文章,它向您展示了如何递归调用lambda委托。这是代码。谢谢你,克里斯
Func<int, int> factoral = x => x <= 1 ? 1 : x + factoral(--x);
Func<int, int> factoral = null;
factoral = x => x <= 1 ? 1 : x + factoral(--x);
Func factoral=x=>x我使用LINQ的groupby做了一些非常类似的事情
我不使用LINQ的查询语法,因此如果这是错误的,请原谅:
var results = from c in comps
group c by c.ParentCompetitionID into g
select new { ParentId = g.Key, ChildId = g };
当然,如果您的类看起来像:
class Competition {
int Id;
string Description;
Competition ParentCompetition;
}
然后,您可以按整个竞争对手进行分组,而不是仅按ID进行分组,这使得生成XML更快、更容易
var results = from c in comps
group c by c.ParentCompetition into g
select new { Parent = g.Key, Child = g };
班级竞赛
{
int ID{get;set;}
int ParentID{get;set;}
IEnumerable子项{get;set;}
}
公共IEnumerableGetChildren(
IEnumerable竞赛,int parentID)
{
数不清的孩子=
其中(c=>c.ParentID==ParentID);
if(children.Count()==0)
返回null;
返回子项。选择(
c=>新竞争{ID=c.ID,Children=GetChildren(c.ID)};
}
然后您可以调用GetChildren,将根的ID作为parentID传递,这将返回一个树结构。您还可以将Competition
对象更改为您选择的XML API
我知道这并不完全是您想要的,但是afaik LINQ不支持递归。尽管如此,LINQ的LIN部分意味着语言集成,这正是我所使用的。而您不能通过单个查询来实现这一点(除非您使用CTE直接调用SQL),您可以将查询数限制为树的深度
代码太长,无法粘贴,但基本步骤如下:
收集根节点并添加到“所有”节点
收集“所有”节点中具有父节点的节点(将列表传递到查询)
将步骤2中的节点添加到“所有”节点
重复2-3,直到步骤2返回0个节点(我认为应该是树的深度+1)
您可以在步骤2中最小化传递给查询的节点数量。SQL server往往会以2000多个条目的列表爆炸。(SQL Compact没有这方面的问题)。不知道如何编写递归LINQ。但我认为这里实际上不需要递归。树可以通过两个步骤构建:
Dictionary<int, Competition> dic = comps.ToDictionary(e => e.CompetitionID);
foreach (var c in comps)
if (dic.ContainsKey(c.ParentCompetitionID))
dic[c.ParentCompetitionID].Children.Add(c);
var root = dic[1];
Dictionary dic=comps.ToDictionary(e=>e.CompetitionID);
foreach(公司中的var c)
if(dic.ContainsKey(c.家长竞争ID))
dic[c.ParentCompetitionID].Children.Add(c);
var root=dic[1];
根变量现在包含完整的树
这里有一个完整的样本要测试:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication2
{
class Competition
{
public int CompetitionID;
public int ParentCompetitionID;
public List<Competition> Children=new List<Competition>();
public Competition(int id, int parent_id)
{
CompetitionID = id;
ParentCompetitionID = parent_id;
}
}
class Program
{
static void Main(string[] args)
{
List<Competition> comps = new List<Competition>()
{
new Competition(1, 0),
new Competition(2,1),
new Competition(3,1),
new Competition(4,2),
new Competition(5,3)
};
Dictionary<int, Competition> dic = comps.ToDictionary(e => e.CompetitionID);
foreach (var c in comps)
if (dic.ContainsKey(c.ParentCompetitionID))
dic[c.ParentCompetitionID].Children.Add(c);
var root = dic[1];
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
命名空间控制台应用程序2
{
班级竞赛
{
公共国际竞争d;
公共竞争ID;
public List Children=new List();
公开竞赛(国际id、国际家长id)
{
CompetitionID=id;
ParentCompetitionID=父项id;
}
}
班级计划
{
静态void Main(字符串[]参数)
{
列表comps=新列表()
{
新竞赛(1,0),
新竞赛(2,1),
新比赛(3,1),
新竞赛(4,2),
新比赛(5,3)
};
字典dic=comps.ToDictionary(e=>e.CompetitionID);
foreach(公司中的var c)
if(dic.ContainsKey(c.家长竞争ID))
dic[c.ParentCompetitionID].Children.Add(c);
var root=dic[1];
}
}
}
您可以得到一个树状结构,将LINQ和递归与委托相结合。在本例中,我使用如下XML结构:
<Competitions>
<Competition ID="1" />
<Competition ID="2" ParentCompetitionID="1" />
<Competition ID="3" ParentCompetitionID="1" />
<Competition ID="4" />
</Competitions>
class Competition
{
public int CompetitionID { get; set; }
public IEnumerable<Competition> Childs { get; set; }
}
因此,要以代码形式存储节点数据并方便导航,请创建如下类:
<Competitions>
<Competition ID="1" />
<Competition ID="2" ParentCompetitionID="1" />
<Competition ID="3" ParentCompetitionID="1" />
<Competition ID="4" />
</Competitions>
class Competition
{
public int CompetitionID { get; set; }
public IEnumerable<Competition> Childs { get; set; }
}
班级竞赛
{
公共整数竞争ID{get;set;}
公共IEnumerable子项{get;set;}
}
现在使用Linq to XML将XML文件加载到XDocument中。然后声明一个委托,该委托迭代文档中的所有XML元素,选择id与委托id参数匹配的节点。选择每个节点时,它再次调用委托,传递要查找的父节点的id。它首先从h将id参数设置为null,因此,选择firts根节点:
var doc = XDocument.Load("tree.xml");
//Declare the delegate for using it recursively
Func<int?, IEnumerable<Competition>> selectCompetitions = null;
selectCompetitions = (int? id) =>
{
return doc.Elements("Competitions").Elements().Where(c =>
{
//If id is null return only root nodes (without ParentCompetitionID attribute)
if (id == null)
return c.Attribute("ParentCompetitionID") == null;
else
//If id has value, look for nodes with that parent id
return c.Attribute("ParentCompetitionID") != null &&
c.Attribute("ParentCompetitionID").Value == id.Value.ToString();
}).Select(x => new Competition()
{
CompetitionID = Convert.ToInt32(x.Attribute("ID").Value),
//Always look for childs with this node id, call again to this
//delegate with the corresponding ID
Childs = selectCompetitions(Convert.ToInt32(x.Attribute("ID").Value))
});
};
var competitions = selectCompetitions(null);
var doc=XDocument.Load(“tree.xml”);
//声明用于递归使用的委托
Func=null;
选择竞赛=(int?id)=>
{
返回doc.Elements(“竞赛”).Elements()。其中(c=>
{
//如果id为null,则仅返回根节点(不带ParentCompetitionID属性)
if(id==null)
返回c.Attribute(“ParentCompetitionID”)==null;
其他的
//如果id有值,则查找具有该父id的节点
返回c.Attribute(“ParentCompetitionID”)!=null&&
c、 属性(“ParentCompetitionID”).Value==id.Value.ToString();
}).选择(x=>new Competition()
{
CompetitionID=转换为32(x.Attribute(“ID”).Value),
//始终查找具有此节点id的child,请再次调用此
//具有相应ID的委托
Childs=selectCompetitions(Convert.ToInt3
internal class Competition
{
public int CompetitionID;
public int ParentCompetitionID;
public Competition(int id, int parentId)
{
CompetitionID = id;
ParentCompetitionID = parentId;
}
}
internal class Node
{
public Node(int id, IEnumerable<Node> children)
{
Children = children;
Id = id;
}
public IEnumerable<Node> Children { get; private set; }
public int Id { get; private set; }
}
internal class Program
{
static void Main(string[] args)
{
var comps = new List<Competition>
{
new Competition(1, 0),
new Competition(2, 1),
new Competition(3, 1),
new Competition(4, 2),
new Competition(5, 3)
};
Node root = ToTree(0, comps);
}
static readonly Func<int, IEnumerable<Competition>, Node> ToTree =
(nodeId, competitions) => new Node(nodeId, from c in competitions where c.ParentCompetitionID == nodeId select ToTree(c.CompetitionID, competitions));
}