[英]How to find the path that a recursive function took using c#?
我有一个对象,该对象的属性允许我创建同一对象(嵌套对象)的另一个实例。我需要搜索列表,找出对象在嵌套中的首次出现。
一旦找到一个,我想找出找到它的确切路径。
我有以下课程
public class ReportRelationMapping : IReportRelationMapping
{
string Name { get; set; }
IReportRelation LocalRelation { get; set; }
IReportRelation ForeignRelation { get; set; }
IReportRelationMapping RelatedThrough { get; set; } // This creates and instance of itself creating a chain
}
假设我有上述课程的以下列表
List<IReportRelationMapping> myList = new List<ReportRelationMapping>
{
new ReportRelationMapping
{
Name = "A",
LocalRelation = ...,
ForeignRelation = ...
RelatedThrough = new ReportRelationMapping
{
Name = "B",
LocalRelation = ...,
ForeignRelation = ...
RelatedThrough = new ReportRelationMapping
{
Name = "C",
LocalRelation = ...,
ForeignRelation = ...
RelatedThrough = new ReportRelationMapping
{
Name = "D",
LocalRelation = ...,
ForeignRelation = ...
RelatedThrough = new ReportRelationMapping
}
}
}
}
,new ReportRelationMapping
{
Name = "E",
LocalRelation = ...,
ForeignRelation = ...
RelatedThrough = new ReportRelationMapping
{
Name = "F",
LocalRelation = ...,
ForeignRelation = ...
}
}
,new ReportRelationMapping
{
Name = "G",
LocalRelation = ...,
ForeignRelation = ...
}
}
我需要找出查找第一个“ C”所用的确切路径。 我需要获得以下清单
List<ReportRelationMapping> pathToTarget = new List<ReportRelationMapping>
{
new ReportRelationMapping
{
Name = "A",
LocalRelation = ...,
ForeignRelation = ...
}
,new ReportRelationMapping
{
Name = "B",
LocalRelation = ...,
ForeignRelation = ...
}
,new ReportRelationMapping
{
Name = "C",
LocalRelation = ...,
ForeignRelation = ...
}
}
我编写了一个递归方法,该方法可以正确找到“ C”,但不能捕获正确使用的路径。 这是我所做的
private void GetAvailableRelation(List<IReportRelationMapping> relationsMappings, string belongsTo, ref List<IReportRelationMapping> pathToTarget)
{
var requiredRelation = relationsMappings.Where(x => x.LocalRelation.TableAlias == belongsTo || x.ForeignRelation.TableAlias == belongsTo).FirstOrDefault();
if (requiredRelation == null)
{
//At this point we know there is no match on the top level, lets check the nested level
var relatedRelations = new List<IReportRelationMapping>();
foreach (var relationsMapping in relationsMappings)
{
if (relationsMapping.RelatedThrough != null)
{
relatedRelations.Add(relationsMapping.RelatedThrough);
}
}
if (relatedRelations.Any())
{
GetAvailableRelation(relatedRelations, belongsTo, ref pathToTarget);
}
else
{
// Since we reached the last node and count not find a matching, reset the pathToTarget list
pathToTarget.Clear();
}
}
if (requiredRelation != null)
{
//Check if relation exists before adding it.
pathToTarget.Add(requiredRelation);
}
}
The problem seems to be that after I call the method `GetAvailableRelation` recursively, the value of `requiredRelation` will become `null` when the last line come there is nothing to add to my `pathToTarget`.
问题:如何正确生成pathToTarget
列表?
简短的答案是:不要变异。
您正在传递对变量的引用,该变量本身就是对可变列表的引用,然后对其进行突变。 这是造成递归代码混乱的秘诀。 (您从不对引用进行变异; 如果您从不对变量进行变异, 为什么要通过ref传递变量?我想您可能对C#中的引用语义有根本的误解。)
相反,原因如下。 从基础开始:
好吧,现在想想:既然您已选择遵循这些规则,那么输入和输出必须是什么? 输入是某些东西的不可变序列。 输出是某些东西的不可变序列。 大。
由于这是一种递归方法,因此我们知道以下其他事实:
现在您可以回答以下问题:
让我们画出一些答案:
现在可以编写您的方法了吗?
最好的解决方案是使用一个临时对象模拟堆栈来递归代码,当您找到对象时,该堆栈将包含指向它的确切路径。
我认为我通过尝试遵循埃里克·利珀特(Eric Lippert)正确答案中列出的规则解决了这个问题。
这是似乎起作用的功能。
private List<IReportRelationMapping> GetAvailableRelation(List<IReportRelationMapping> relationsMappings, string belongsTo)
{
List<IReportRelationMapping> pathToTarget = new List<IReportRelationMapping>();
var requiredRelation = relationsMappings.Where(x => x.LocalRelation.TableAlias == belongsTo || x.ForeignRelation.TableAlias == belongsTo).FirstOrDefault();
if (requiredRelation != null)
{
//Handle the top level
pathToTarget.Add(requiredRelation);
} else {
//At this point we know there is no match on the top level, lets check the nested level
var relatedRelations = new List<IReportRelationMapping>();
foreach (var relationsMapping in relationsMappings)
{
if (relationsMapping.RelatedThrough != null)
{
//Add the path in between previous and next
pathToTarget.Add(relationsMapping);
foreach (var subRelation in relationsMapping.RelatedThrough)
{
relatedRelations.Add(subRelation);
}
}
}
if (relatedRelations.Any())
{
//Now we know there is at least one more nested level that we need to check
var subPathsToTarget = GetAvailableRelation(relatedRelations, belongsTo);
if (subPathsToTarget.Any())
{
//prepend the current items to the path
pathToTarget = pathToTarget.Concat(subPathsToTarget).ToList();
}
else
{
//At this point we know we reach the final node and the item was not found.
pathToTarget.Clear();
}
}
}
return pathToTarget;
}
更新
现在我的对象接受了这样的RelatedThrough
列表
public class ReportRelationMapping : IReportRelationMapping
{
public string Name { get; set; }
public SqlJoinStatement JoinType { get; set; }
public IReportRelation LocalRelation { get; set; }
public IReportRelation ForeignRelation { get; set; }
public List<IReportRelationMapping> RelatedThrough { get; set; }
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.