0

linq expressions is to complex for me when i need to do complex searches over list.

let's say i have List

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

How to filter objects id by max length, if there are more than one index, then filter by max width, if there are more than one index, then filter by max depth, if there more then one index return first one.

i found max values:

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

then i used for loop to get values. And it's ok, but after each loop i have to create another list to get another value and etc.

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

How to do that elegant linq way with if statements if possible?

Marius
  • 25
  • 1
  • 13
  • 6
    Please correct your examples before posting. Make sure they will compile if someone will copy-paste to his editor. – SᴇM Nov 28 '18 at 12:49
  • @HimBromBeere Do he actually wanted to ask about `OrderBy`? I guess he was asking about something like `GroupBy`. Edit: If he will order by those 3 conditions and take first one (or last), it will be the same. – SᴇM Nov 28 '18 at 13:00
  • 1
    That is not a [mcve]. It isn't complete. Your `Object` class **still** doesn't compile. Where did the `boxes` variable come from? You didn't specify sample inputs or expected outputs. – mjwills Nov 28 '18 at 21:07
  • What do you want to achieve? Your method is called largestSurfaceBox, but what you are doing does not provide you a box with largest surface because that box does not necessarily have largest width. You need to calculate surface of each box and select maximum – Slava Nov 28 '18 at 23:17
  • @Slava i can't do that because priority: 1. length, 2.width 3.depth. – Marius Nov 29 '18 at 08:21

1 Answers1

0

Sounds like you are looking for "MaxBy" with multiple conditions. There are few possible options using LINQ extensions. The simple and probably most inefficient is to order and get the first or last item :

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

Another option is to implement custom comparer on your class so that you can do just boxes.Max(),
or use class that already implements it such as Tuple (results in Exception if collection is empty) :

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

The above is also not the most efficient, as it creates a Tuple for each item, but will probably be fast enough. Most efficient should be a single for loop to get the max item without LINQ.

Slai
  • 22,144
  • 5
  • 45
  • 53