简体   繁体   中英

Linq sorting with nullable object

could you please help me! I have object list like:

item[0].title = apple
item[0].data.weight = 1

item[1].title = lemon
item[1].data = null

item[2].title = melon
item[2].data.weight = 3

I would like to sort it (ASC and DESC) by weight with null data. I tried like this:

item.OrderBy(x => x.data == null).ThenBy(x => x.data.weight); // failed
item.Where(x => x.data != null).OrderBy(x => x.data.weight); // ok, but as result only two records

So how i can sort items and receive all results. ASC at first should be data with null. DESC at first data with max weight and null at the end of the list.

item.OrderBy(x => x.data == null).ThenByDescending(x => x.data == null ? 0 : x.data.weight);

我假设weight是一个int,否则提供基于类型的默认值。

Given you're only shipping fruit, and not, say, light, you can treat items having null data as having weight 0. Alternatively, just pick any value that's lower than the possible, valid values in order to put the null items at the top when sorting ascendingly.

You can express that like this:

var ordered = item.OrderBy(x => x.data == null ? 0 : x.data.weight);

You could use something like this: (assuming C# 6 or above)

item.OrderBy(x => x.data?.weight ?? int.MinValue);

This makes use of the new C#6 null-conditional and null-coalescing operators - if you need something applicable in lower versions of C#, you can use a ternary operator, like this:

item.OrderBy(x => x.data != null ? x.data.weight : int.MinValue);

If it's possible that you could have x.data.weight being int.MinValue , then you would need to do something like what you were doing before, but the second linq method should make use of the above lambda/s.

You can do this a few ways, one way would be to have a value replacing the null values using ternary conditional operator on the order by or filtering out the items without a value and concatenating them to the enumerable after you've sorted the objects with values.

By conditionally providing a value for items with null

This is, in my opinion, the best way, and it performs better. You only enumerate over the collection once, versus the other method where you enumerate to determine if each element has a value then order, and then check for the items without a value

item.OrderBy(x => x.data != null ? x.data.weight : int.MinValue)

Filtering and then concatenating the items without a value

There are times where this could possibly be the better solution. One example would be if you want to use a different method for ordering the values when they are missing the property you are looking for.

item.Where(x => x.data != null)
    .OrderBy(x => x.data.weight)
    .Concat(item.Where(a=>a.data == null))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM