【问题标题】:C#, get object indexes from List, by multiple conditions using LinqC#,通过使用 Linq 的多个条件从 List 获取对象索引
【发布时间】:2018-11-30 00:45:28
【问题描述】:

当我需要对列表进行复杂搜索时,linq 表达式对我来说太复杂了。

假设我有列表

public class Object {
    var length;
    var height;
    var depth;
}

如何按最大长度过滤对象id,如果有多个索引,则按最大宽度过滤,如果有多个索引,则按最大深度过滤,如果有多个索引返回第一个。

我找到了最大值:

float maxWidth = boxes.Max(x => x.width);
float maxHeight = boxes.Max(x => x.height);
float maxDepth = boxes.Max(x => x.depth);

然后我使用 for 循环来获取值。没关系,但是在每个循环之后我必须创建另一个列表来获取另一个值等等。

private GameObject largestSurfaceBox()
{

    //find max length.width, height box
    float maxWidth = boxes.Max(x => x.GetComponent<Box>().dimensions.x);
    List<GameObject> maxWidthBoxes = new List<GameObject>();

    for (int i = 0; i < boxes.Count; i++) {
        if (System.Math.Abs(boxes[i].GetComponent<Box>().dimensions.x - maxWidth) < float.Epsilon) {
            maxWidthBoxes.Add(boxes[i]);
        }
    }

    float maxHeight = maxWidthBoxes.Max(x => x.GetComponent<Box>().dimensions.y);
    List<GameObject> maxHeightBoxes = new List<GameObject>();

    for (int i = 0; i < maxWidthBoxes.Count; i++) {
        if (System.Math.Abs(maxWidthBoxes[i].GetComponent<Box>().dimensions.y - maxHeight) < float.Epsilon) {
            maxHeightBoxes.Add(boxes[i]);
        }
    }

    List<GameObject> maxDepthBoxes = new List<GameObject>();
    float maxDepth = maxHeightBoxes.Max(x => x.GetComponent<Box>().dimensions.z);

    for (int i = 0; i < maxHeightBoxes.Count; i++) {
        if (System.Math.Abs(maxHeightBoxes[i].GetComponent<Box>().dimensions.z - maxDepth) < float.Epsilon) {
            maxDepthBoxes.Add(boxes[i]);
        }
    }

    return maxDepthBoxes[0];
}

如果可能的话,如何用 if 语句做那种优雅的 linq 方式?

【问题讨论】:

  • 请在发布前更正您的示例。如果有人将复制粘贴到他的编辑器,请确保它们会编译。
  • @HimBromBeere 他真的想问OrderBy吗?我猜他问的是GroupBy之类的问题。编辑:如果他将按这 3 个条件订购并拿第一个(或最后一个),那将是相同的。
  • 那不是minimal reproducible example。它不完整。您的 Object仍然 无法编译。 boxes 变量从何而来?您没有指定示例输入或预期输出。
  • 你想达到什么目的?您的方法称为最大表面框,但您所做的并未为您提供具有最大表面的框,因为该框不一定具有最大宽度。您需要计算每个盒子的表面并选择最大值
  • @Slava 我不能这样做,因为优先级:1.长度,2.宽度 3.深度。

标签: c# list linq


【解决方案1】:

听起来您正在寻找具有多个条件的“MaxBy”。使用 LINQ 扩展的可能选项很少。最简单且可能效率最低的方法是订购并获取第一个或最后一个项目:

GameObject result = boxes.OrderBy(x => x.width)
                          .ThenBy(x => x.height)
                          .ThenBy(x => x.depth)
                          .LastOrDefault();

另一种选择是在你的班级上实现custom comparer,这样你就可以只做boxes.Max()
或使用已经实现它的类,例如Tuple(如果集合为空,则会导致异常):

GameObject result = boxes.Max(x => Tuple.Create(x.width, x.height, x.depth, x)).Item4;

上述也不是最有效的,因为它为每个项目创建一个Tuple,但可能会足够快。最有效的应该是单个 for 循环,以在不使用 LINQ 的情况下获取最大项目。

【讨论】:

  • MoreLinq 的MaxBy 可能在这里感兴趣。
  • @Slai 你只需使用三个MaxBy 调用(宽度、高度、深度)。
  • MaxBy 返回多个值已有一段时间了。 github.com/morelinq/MoreLINQ/issues/328
猜你喜欢
  • 2014-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-19
  • 1970-01-01
  • 2014-02-11
  • 1970-01-01
  • 2013-10-07
相关资源
最近更新 更多