C# 用于搜索集合的Lambda表达式(或其他方式)

C# 用于搜索集合的Lambda表达式(或其他方式),c#,lambda,C#,Lambda,我有一个包含行星及其卫星的儿童收藏。 它是一个集合,但实际上代表了一个树状结构。为了简单起见,我只展示了两个层次的树,但每个行星或月球都可能有更多的化学元素,所以我使用两个层次的树只是为了简单 Mercury Venus Mars - Deimos - Phobos Jupiter - Europa - Ganymede - Io 我知道如何将此集合转换为列表,我只使用 var myList = myCollection.Values.ToList(); 我想在此列

我有一个包含行星及其卫星的儿童收藏。
它是一个集合,但实际上代表了一个树状结构。为了简单起见,我只展示了两个层次的树,但每个行星或月球都可能有更多的化学元素,所以我使用两个层次的树只是为了简单

Mercury

Venus

Mars
  - Deimos
  - Phobos

Jupiter
  - Europa
  - Ganymede
  - Io
我知道如何将此集合转换为列表,我只使用

var myList = myCollection.Values.ToList();
我想在此列表中搜索名称中包含“m”的每个项目。如果父代的名字中没有“m”,但它的子代“moons”有,我想把这个子代(moon)和它的父代(planet)也包括在内。如果是木星,我会把木星和木卫三都包括在我的名单中

因此,我对“m”的搜索将返回以下列表

{水星、火星、代莫斯、木星、木卫三}

我更喜欢使用lambda,但不需要这样做

更新:结构

BodyNode
-ID      [Guid]
-Name    [string]
-IsChild [bool]
-Parent  [BodyNode]
-Children[BodyList ObservableCollection of BodyNode]

BodyTreeNode : BodyNode
-Expanded   [bool]
-Selected   [bool]
-Enabled    [bool]

如果确实确定数据是树状结构,则可以执行以下操作(无需检查周期):

然后将其用作:

var r = new List<Base>();
myList.Foreach(o => GetNodes(o, r, (b) => b.Name.Contains("m")); 
var r=newlist();
Foreach(o=>GetNodes(o,r,(b)=>b.Name.Contains(“m”);
var MRecords=myList.Where(x=>x.toUpper().Contains(“M”);
var result=new HashSet();//我以前没有使用HashSet,但正如[here]中所述(http://stackoverflow.com/questions/6391738/what-is-the-difference-between-hashsett-and-listt)消除重复项
foreach(MRecords中的var记录)
{
结果.添加(记录);
var ParentLooper=记录;
while(ParentLooper.parent!=null)//我假设根的父节点为null
{
添加(ParentLooper.parent);
ParentLooper=ParentLooper.parent;
}
}
返回结果;

就我个人而言,我建议在处理这样的树实体时使用包含自己自定义类的
IEnumerables
对象。你的
行星和你的月亮似乎都有相同的属性,所以它们本质上都是类
行星,我制作了一个私人模型课程,如下所示:

private class Planet
        {
            public string Name { get; set; } = string.Empty;
            public IEnumerable<Planet> Children { get; set; } = new List<Planet>();
        }
私人类行星
{
公共字符串名称{get;set;}=string.Empty;
public IEnumerable子项{get;set;}=new List();
}
这使得Lambdas的使用更加简单。我没有测试这个,但是如果它不正确,它就很接近,应该可以让您达到:

      IEnumerable<Planet> myCollection = new List<Planet>();
      myCollection = LetThereBeLight(true); //method to populate the list
      var myList = myCollection.ToList().Where(t => t.Name.ToUpper().Contains("M"));
      myList.ToList().AddRange
                            (
                             myCollection.SelectMany(t => t.Children.Where
                                    (
                                      v => v.Name.ToUpper().Contains("M")).Distinct()
                                    )
                            );
IEnumerable myCollection=new List();
myCollection=letTheRelieght(true);//填充列表的方法
var myList=myCollection.ToList(),其中(t=>t.Name.ToUpper().Contains(“M”);
myList.ToList().AddRange
(
myCollection.SelectMany(t=>t.Children.Where
(
v=>v.Name.ToUpper().Contains(“M”).Distinct()
)
);

你可以把它全部做成一个Lambda,但如果不想把它全部压缩成一行,阅读起来就很困难。如果你想表示月亮的不同,比如加一个“-”,这将给你一个
IEnumerable
对于名称
字符串
,您可以循环查看每个
星球的
子集合。您可能需要确保只使用
myList.Distinct()
,因为复制在这里是完全可能的。

假设您拥有集合中所有元素的序列。然后您可以在该序列上使用
Where
,或任何其他序列运算符。因此,您最好的选择是构建该序列:

static class Extensions {
 public static IEnumerable<Nodes> Flatten(this IEnumerable<Node> nodes)
 {
  foreach(var node in nodes)
  {
    yield return node;
    foreach (var child in node.Children.Flatten())
      yield return child;
  }
 }
}
这是名称中包含m的每个元素的列表:

或者使用lambda

var results = myCollection.Values.Flatten()
  .Where(node => ... and so on ... );
现在,您需要的是一个列表,其中包含名称中有m的每个元素,或者任何子元素都有m

var results = from node in myCollection.Values.Flatten()
              where node.Name.Contains("m") || node.Children.Flatten().Any(node.Name.Contains("m"))
              select node;

现在,这是相当低效的——你知道为什么吗?——但它确实起到了作用。现在你有了一些可以分析的东西,如果你真的需要的话,你可以尝试提高效率。

使用
DFS
搜索树,如果名称包含“m”,则将其添加到列表中。如果你想要不区分大小写的比较,你应该改为使用在一些答案中建议了
ToUpper
/
ToLower
的组合。如果您希望它看起来好看,可以创建一个扩展方法:
public static bool Contains(此字符串源、字符串值、字符串比较)=>source.IndexOf(值、比较)>-1;
并且不要忘记参数验证。谢谢链接,但是如果其子级有“M”,那么这将如何包括没有“M”的父级。看起来这只包括所有带“M”的itesm(父级和子级)因为这是MRecords将包含的内容抱歉,我因为社区xD而快速键入,返回结果而不是MRecords MRecords是一个帮助列表,用于获取所有具有M的记录。然后在MRecords上循环,将它们及其父项添加到最终结果中(这是一个消除重复项的哈希集HMMM,虽然我最能理解您的解决方案,但我似乎无法使用它。问题是,在您的解决方案记录中,将是我的BodyTreeNode对象,但ParentLooper.parent是我的BodyNode对象。BodyTreeNode从BodyNode派生,但我无法在您的while中执行这两行操作。)循环。谢谢,但我正在努力遵循它。另外,我没有树类型,我有一个转换为列表的集合。所有对象都有一个表示其子对象的
List
?它们是否派生自基类?请查看我的编辑,让我知道它是否适用于您。但我上面的列表仅包括带有“M”的项在它们里面。如果行星没有“M”,但只有它的卫星有“M”,那该怎么办?它们应该都包括在内(即木星和它的卫星木卫三)。我看上面没有包括这一点。或者我遗漏了什么?哦,你是对的,我的例子
static class Extensions {
 public static IEnumerable<Nodes> Flatten(this IEnumerable<Node> nodes)
 {
  foreach(var node in nodes)
  {
    yield return node;
    foreach (var child in node.Children.Flatten())
      yield return child;
  }
 }
}
var results = from node in myCollection.Values.Flatten()
              where node.Name.ToLower().Contains("m")   
              select node;
var results = myCollection.Values.Flatten()
  .Where(node => ... and so on ... );
var results = from node in myCollection.Values.Flatten()
              where node.Name.Contains("m") || node.Children.Flatten().Any(node.Name.Contains("m"))
              select node;