LINQ 和递归

发布于 2024-10-04 03:45:19 字数 768 浏览 3 评论 0原文

请考虑以下问题:

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;
}

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

Consider the following:

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;
}

Is there any way that FindBoxBySize() can be compacted using LINQ? Also: comments on my code are welcome. I don't do much recursion, so I might have missed something in my implementation.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

深府石板幽径 2024-10-11 03:45:19

我还采用扩展方法方法,但使用迭代器方法:

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);

I'd also take the extension method approach, but use an iterator method:

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;
            }
        }
    }
}

Your FindBoxBySize method now becomes:

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

Your original calling code works without modification:

var small = FindBoxBySize(box, BoxSize.Small);
朦胧时间 2024-10-11 03:45:19

扩展方法:

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);

Extension methods:

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);
    }
}

Usage:

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);
初见终念 2024-10-11 03:45:19

如果你想使用 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);

If you want to use LINQ, you could do something like this (untested):

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);
∞梦里开花 2024-10-11 03:45:19

来使您的递归更清晰(在我看来)

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;
} 

您可以通过编写As for LINQ: LINQ does not come with a good way to handle recursive data Structures 。可以通过向 google 询问“LINQ 递归”来找到几种不同的扩展方法来补救,但我不确定它们是否在这种情况下增加了清晰度。

You could make your recursion a little clearer (in my eyes) by writing

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;
} 

As for LINQ: LINQ does not come with a good way to handle recursive data structures. Several different Extension methods to remedy that can be found by asking google for "LINQ recursion", but I am unsure if they add clarity in this case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文