我有一个课程如下:
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来一次传递一个顶级功能。
我确信有一种更简单的方法可以做到这一点,我该如何正确地做到这一点?
答案 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);
}
}
}