2010-11-23 72 views
5

考虑以下几点:LINQ和递归

public class Box 
{ 
    public BoxSize Size { get; set; } 

    public IEnumerable<Box> Contents { get; set; } 
} 

Box FindBoxBySize(Box box, BoxSize size) 
{ 
    Box _foundBox = null; 

    Action<IEnumerable<Box>> _recurse = null; 

    _recurse = new Action<IEnumerable<Box>>(boxes => 
    { 
     foreach (var _box in boxes) 
     { 
      if (_box.Size == size) 
      { 
       _foundBox = _box; 

       return; 
      } 

      if (_box.Contents != null) _recurse(_box.Contents); 
     } 
    }); 

    _recurse(box.Contents); 

    return _foundBox; 
} 

有没有什么办法可以FindBoxBySize()使用LINQ被压缩?另外:欢迎对我的代码发表评论。我没有做太多的递归,所以我可能在我的实现中遗漏了一些东西。

回答

5

我还需要扩展方法的方法,但使用iterator方法:

public static class BoxEx 
{ 
    public static IEnumerable<Box> Flatten(this Box box) 
    { 
     yield return box; 
     if (box.Contents != null) 
     { 
      foreach (var b in box.Contents.SelectMany(b2 => Flatten(b2))) 
      { 
       yield return b; 
      } 
     } 
    } 
} 

FindBoxBySize方法现在变成了:

Box FindBoxBySize(Box box, BoxSize size) 
{ 
    return (from b in box.Flatten() 
      where b.Size == size 
      select b).FirstOrDefault(); 
} 

你的原始调用代码工作无需修改:

var small = FindBoxBySize(box, BoxSize.Small); 
2

扩展方法:

class Box 
{ 
    public IEnumerable<Box> GetBoxes() 
    { 
     // avoid NullReferenceException 
     var contents = this.Contents ?? Enumerable.Empty<Box>(); 

     // do the recursion 
     return contents.SelectMany(b => b.GetBoxes()).Concat(contents); 
    } 

    public Box GetBox(int size) 
    { 
     return this.GetBoxes().FirstOrDefault(b => b.Size == size); 
    } 
} 

用法:

var box_with_box = new Box { Contents = new[] { new Box() { Size = 10 } } }; 
var box = new Box { Contents = new[] { box_with_box, box_with_box } }; 

Box box10 = box.GetBox(10); 
+0

我认为它的确如此。但请注意我的诀窍;我真的很喜欢那里尽可能少的“循环”,所以无论何时找到一场比赛,我想终止。 – roosteronacid 2010-11-23 14:49:00

1

如果你想使用LINQ,你可以做这样的事情(未经测试):

public static IEnumerable<Box> GetBoxesRecursive(this Box box) 
{ 
    if(box == null) 
     throw new ArgumentNullException("box"); 

    var children = box.Contents ?? Enumerable.Empty<Box>(); 

          // use lambda in C# 3.0  
    var recursiveChildren = children.SelectMany(GetBoxesRecursive); 

    return new[] { box }.Concat(recursiveChildren);          
} 

...  

Box desiredBox = myBox.GetBoxesRecursive() 
         .FirstOrDefault(b => b.Size == desiredSize); 
0

你可以做你的递归更清晰一些(在我眼里)通过编写

Box FindBoxBySize(Box box, BoxSize size) 
{ 
    if (box.Size == size) 
     return box; 

    foreach (var child in box.Contents) 
    { 
     var foundBox = FindBoxBySize(child, size); 
     if(foundBox != null) 
      return foundBox; 
    } 

    return null; 
} 

至于LINQ:LINQ没有处理递归数据结构的好方法。可以通过向谷歌询问“LINQ递归”来找到几种不同的扩展方法来弥补,但我不确定这些方法是否增加了这种情况下的清晰度。