문제
누군가 C#에서 트리 구조를 탐색하기 위해 재귀적 람다 식을 구현하는 방법을 보여줄 수 있습니까?
해결책
좋아, 드디어 자유시간을 찾았어.
여기 있습니다:
class TreeNode
{
public string Value { get; set;}
public List<TreeNode> Nodes { get; set;}
public TreeNode()
{
Nodes = new List<TreeNode>();
}
}
Action<TreeNode> traverse = null;
traverse = (n) => { Console.WriteLine(n.Value); n.Nodes.ForEach(traverse);};
var root = new TreeNode { Value = "Root" };
root.Nodes.Add(new TreeNode { Value = "ChildA"} );
root.Nodes[0].Nodes.Add(new TreeNode { Value = "ChildA1" });
root.Nodes[0].Nodes.Add(new TreeNode { Value = "ChildA2" });
root.Nodes.Add(new TreeNode { Value = "ChildB"} );
root.Nodes[1].Nodes.Add(new TreeNode { Value = "ChildB1" });
root.Nodes[1].Nodes.Add(new TreeNode { Value = "ChildB2" });
traverse(root);
다른 팁
적절한 솔루션, 실제로 많은 함수형 프로그래밍 언어의 관용적 솔루션은 다음을 사용하는 것입니다. 고정 소수점 결합기.간단히 말해서:고정 소수점 결합자는 "재귀적인 익명 함수를 어떻게 정의합니까?"라는 질문에 답합니다.그러나 해결책은 너무나 간단해서 이를 설명하기 위해 전체 기사가 작성되었습니다.
간단하고 실용적인 대안은 C의 장난을 "시간을 거슬러 올라가는 것"입니다.정의 전 선언.다음을 시도해 보십시오(“계속” 함수).
Func<int, int> fact = null;
fact = x => (x == 0) ? 1 : x * fact(x - 1);
매력처럼 작동합니다.
또는 클래스 객체에 대한 선주문 트리 탐색의 경우 TreeNode
구현하는 IEnumerable<TreeNode>
적절하게 자식을 검토하려면 다음을 수행하십시오.
Action<TreeNode, Action<TreeNode>> preorderTraverse = null;
preorderTraverse = (node, action) => {
action(node);
foreach (var child in node) preorderTraverse(child, action);
};
간단한 대안은 C와 C++의 익살스러운 방식으로 "시간을 거슬러 올라가는 것"입니다.정의 전 선언.다음을 시도해 보세요:
Func<int, int> fact = null; fact = x => (x == 0) ? 1 : x * fact(x - 1);
매력처럼 작동합니다.
예, 한 가지 주의 사항이 있지만 작동합니다.C#에는 변경 가능한 참조가 있습니다.따라서 실수로 다음과 같은 일을 하지 않도록 주의하세요.
Func<int, int> fact = null;
fact = x => (x == 0) ? 1 : x * fact(x - 1);
// Make a new reference to the factorial function
Func<int, int> myFact = fact;
// Use the new reference to calculate the factorial of 4
myFact(4); // returns 24
// Modify the old reference
fact = x => x;
// Again, use the new reference to calculate
myFact(4); // returns 12
물론 이 예제는 약간 인위적이지만 가변 참조를 사용할 때 이런 일이 발생할 수 있습니다.다음의 결합자를 사용하는 경우 아쿠님의 링크로는 불가능합니다.
계층 구조를 나타내는 Children 컬렉션을 포함하는 신화적인 개체 TreeItem을 가정합니다.
public void HandleTreeItems(Action<TreeItem> item, TreeItem parent)
{
if (parent.Children.Count > 0)
{
foreach (TreeItem ti in parent.Children)
{
HandleTreeItems(item, ti);
}
}
item(parent);
}
이제 이를 호출하고 항목 하나를 처리하는 람다를 콘솔에 출력하여 전달합니다.
HandleTreeItems(item => { Console.WriteLine(item.Name); }, TreeItemRoot);