递归列表包含属性

时间:2017-03-03 10:03:02

标签: c# .net

我有一个课程如下:

public class Feature
{
    public string Name { get; set; }

    public string DisplayName { get; set; }

    public List<Feature> SubFeatures { get; set; } = new List<Feature>();
}

然后我有List<Feature> features = new List<Feature>;我存储了所有功能。

现在,我想知道我的Feature变量中是否存在特定的features(按名称)。

但是,它可以存在于SubFeature的{​​{1}}的任何级别(SubFeature)。

我得到的最接近的是:

SubFeature

但它涉及到public bool FeatureExists(Feature feature, string name) { return feature.Name == name || feature.SubFeatures.Select(subFeature => FeatureExists(subFeature, name)).Any(result => result); } 的来电者必须使用for来一次传递一个顶级功能。

我确信有一种更简单的方法可以做到这一点,我该如何正确地做到这一点?

5 个答案:

答案 0 :(得分:3)

定义一个这样的递归方法:

public IEnumerable<Feature> FeatureAndSubFeatures(Feature feature)
{
    yield return feature;

    foreach (var subFeature in feature.SubFeatures)
    {
        foreach (var child in FeatureAndSubFeatures(subFeature))
        {
            yield return child;
        }
    }
}

然后使用它:

FeatureAndSubFeatures(feature).Any(x => x.Name == name);

另一种选择是将此方法放在Feature本身上,称为SelfAndSubFeaturesRecursive()。

这种方法 - 编写一种递归展平树的方法,而不是编写特定的方法来搜索具有给定名称的要素 - 是灵活的,因为您可以使用它根据任何标准在树中搜索任何节点,或任何节点子集,而不是专门用于查找具有特定名称的节点。

您也可以编写它以开始使用一系列功能。类似的东西:

public IEnumerable<Feature> FeaturesAndSubFeatures(IEnumerable<Feature> features)
{
    foreach (var feature in features)
    {
        yield return feature;

        foreach (var child in FeaturesAndSubFeatures(feature.SubFeatures))
        {
            yield return child;
        }
    }
}

这仅在您始终使用一组功能开始时才有用,但在您执行此操作时会保存SelectMany

答案 1 :(得分:1)

我尽可能避免递归。这是一个没有的版本:

public bool FeatureExists(Feature feature, string name)
{
    var featureQueue = new Queue<Feature>();
    featureQueue.Enqueue(feature);
    while (featureQueue.Count > 0)
    {
        Feature current = featureQueue.Dequeue();
        if (feature.Name == name)
            return true;
        foreach (Feature f in current.SubFeatures)
            featureQueue.Enqueue(f);
    }
    return false;
}

如果您发现这样的可读性较低,您可以使用通用扩展方法并在需要递归检查时使用它,例如:

public static class Extensions
{
    public static bool RecursiveCheck<T>(this T rootItem, Func<T, IEnumerable<T>> getChildrenFunc, Func<T, bool> predicate)
    {
        var queue = new Queue<T>();
        queue.Enqueue(rootItem);
        while (queue.Count > 0)
        {
            T current = queue.Dequeue();
            if (predicate(current))
                return true;
            foreach (T child in getChildrenFunc(current))
                queue.Enqueue(child);
        }
        return false;
    }
}

试验特性:

Feature f1 = new Feature
{
    Name = "1", SubFeatures = new List<Feature> { new Feature {Name="1.1", SubFeatures = new List<Feature> {new Feature {Name= "thename" } } }}
};

这个简单的单行仍然存在:

bool containsName = f1.RecursiveCheck<Feature>(f => f.SubFeatures, f => f.Name == "thename");

答案 2 :(得分:0)

你想要为你做一个单独的递归方法。&#39; 试试这个:

public bool FeatureExists(Feature feature, string name) {
    if(feature.Name == name) {
        return true;
    }   
    if(!feature.SubFeatures.isEmpty) {
        foreach(Feature subFeature in feature.SubFeatures){
            FeatureExists(subFeature, name)
        }
    }
        return false;
    }

答案 3 :(得分:0)

嗯,我不确定这是不是你问的问题,但是如果你想要更清晰的代码,你可以将你的函数编写为扩展方法,并使用LINQ而不是for循环来获得更清晰的代码。

public static bool FeatureExists(this Feature feature, string name)
{
    return feature.Name == name || feature.SubFeatures.Select(subFeature => FeatureExists(subFeature, name)).Any(result => result);
}

然后

List<Feature> mainFeatures = new List<Feature>();
mainFeatures.Any(obj => obj.FeatureExists("abc"));

如果您希望事件更短且更清晰,您可以考虑将某个功能作为所有功能的父功能,例如母功能,然后再调用您的递归方法。

但无论如何,请考虑将您的方法作为扩展方法。

答案 4 :(得分:0)

以下内容应该遍历所有列表,并使用整个层次结构中包含的所有可能功能填充“result”

 public class Feature
    {
        public string Name { get; set; }

        public string DisplayName { get; set; }

        public List<Feature> SubFeatures { get; set; } = new List<Feature>();
    }

其他课程

List<feature> result = new List<feature>();

public void FindItems(Feature yourFeature)
{
   result.add(yourFeature);
   foreach(Feature feature in yourFeature)
   {
      if(feature.SubFeatures.count != 0)
      {
         foreach(Feature subfeature in feature)
         {
            FindItems(subfeature);
         }
      }
      else
      {
         result.add(feature);
      }
   }
}