首页 > 解决方案 > C#,使用 Linq 通过多个条件从 List 获取对象索引

问题描述

当我需要对列表进行复杂搜索时,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 方式?

标签: c#listlinq

解决方案


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

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

另一种选择是在你的类上实现自定义比较器,这样你就可以做boxes.Max()
或者使用已经实现它的类,例如Tuple(如果集合为空,则会导致异常):

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

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


推荐阅读