順序が昇順でnullが最後であるnull列によるLINQ順序


141

製品のリストを価格でソートしようとしています。

結果セットでは、列ごとに価格の高いものから高いものまで製品をリストする必要がありますLowestPrice。ただし、この列はNULL可能です。

次のようにリストを降順に並べ替えることができます。

var products = from p in _context.Products
   where p.ProductTypeId == 1
   orderby p.LowestPrice.HasValue descending
   orderby p.LowestPrice descending
   select p;

// returns:    102, 101, 100, null, null

しかし、これを昇順に並べ替える方法がわかりません。

// i'd like: 100, 101, 102, null, null

11
orderby p.LowestPrice ?? Int.MaxValue;簡単な方法です。
PostMan

3
@PostMan:はい、簡単OrderByDescending, ThenByです。正しい結果が得られますが、より明確です。
ジェイソン

@ジェイソン、ええ、私はの構文を知りませんでしたorderby、そしてそれを探すために追跡されました:)
PostMan

回答:


160

両方の列を同じ順序で並べてみてください。

orderby p.LowestPrice.HasValue descending, p.LowestPrice

それ以外の場合、各orderbyはコレクションに対する個別の操作であり、毎回それを並べ替えます。

これは、最初に値を持つものを順序付けし、次に「値」の順序で並べる必要があります。


21
よくある間違い、人々はLamda構文で同じことをします-.ThenByの代わりに.OrderByを2回使用します。
DaveShaw

1
これは、上部に値があり、下部にnullフィールドがあるフィールドを注文するために機能しましたorderby p.LowestPrice == null, p.LowestPrice ascending 。これを使用しました: 希望が誰かを助けます。
shaijut 2015

@DaveShawチップをありがとう-特にコメント-とてもきちんと-それを愛する
Demetris Leptos

86

これは、LINQクエリ構文と、それがどのようにLINQメソッド呼び出しに変換されるかを理解するのに役立ちます。

それが判明

var products = from p in _context.Products
               where p.ProductTypeId == 1
               orderby p.LowestPrice.HasValue descending
               orderby p.LowestPrice descending
               select p;

コンパイラによって次のように翻訳されます

var products = _context.Products
                       .Where(p => p.ProductTypeId == 1)
                       .OrderByDescending(p => p.LowestPrice.HasValue)
                       .OrderByDescending(p => p.LowestPrice)
                       .Select(p => p);

これは、あなたが望んでいることとは異なります。これProduct.LowestPrice.HasValuedescending順番に並べ替えてから、コレクション全体Product.LowestPricedescending順番に並べ替えます。

あなたが欲しいのは

var products = _context.Products
                       .Where(p => p.ProductTypeId == 1)
                       .OrderByDescending(p => p.LowestPrice.HasValue)
                       .ThenBy(p => p.LowestPrice)
                       .Select(p => p);

クエリ構文を使用して取得できます。

var products = from p in _context.Products
               where p.ProductTypeId == 1
               orderby p.LowestPrice.HasValue descending,
                       p.LowestPrice
               select p;

クエリ構文からメソッド呼び出しへの変換の詳細については、言語仕様を参照してください。真剣に。それを読んで。


4
+1または単に... LINQクエリ構文を記述しないでください:)それでも良い説明
sehe

18

文字列値の解決策は本当に奇妙です:

.OrderBy(f => f.SomeString == null).ThenBy(f => f.SomeString) 

機能する唯一の理由は、最初の式OrderBy()、、bool値を並べ替えるためです:true/ falsefalse結果は、最初にtrue結果(null可能)が続き、ThenBy()null以外の値をアルファベット順に並べ替えます。

だから、私はこのようなもっと読みやすいものをすることを好みます:

.OrderBy(f => f.SomeString ?? "z")

SomeStringがnullの場合、置き換えられ"z"、すべてがアルファベット順に並べ替えられます。

注:"z"などのZ値よりも優先されるため、これは究極のソリューションではありませんzebra

更新 2016年9月6日-@jornhdコメントについては、これは本当に良い解決策ですが、それでも少し複雑なので、次のような拡張クラスでラップすることをお勧めします。

public static class MyExtensions
{
    public static IOrderedEnumerable<T> NullableOrderBy<T>(this IEnumerable<T> list, Func<T, string> keySelector)
    {
        return list.OrderBy(v => keySelector(v) != null ? 0 : 1).ThenBy(keySelector);
    }
}

そして単純にそれを次のように使用します:

var sortedList = list.NullableOrderBy(f => f.SomeString);

2
厄介な定数がなければ、これはより読みやすいと思います:.OrderBy(f => f.SomeString!= null?0:1).ThenBy(f => f.SomeString)
jornhd

14

この状況では別の選択肢があります。私のリストはobjListであり、順序を指定する必要がありますが、最後にnullを指定する必要があります。私の決定:

var newList = objList.Where(m=>m.Column != null)
                     .OrderBy(m => m.Column)
                     .Concat(objList.where(m=>m.Column == null));

これは、nullの代わりに0のような他の値で結果が必要なシナリオで機能します。
Naresh Ravlani 16

はい。ただ、0にヌルを置き換える
Gurgen Hovsepyan

これが私のために働いた唯一の答えであり、残りはリストの最初にヌルを保持しました。
BMills

9

私はこれに対するLINQソリューションを見つけようとしていましたが、ここの答えからそれを解決することができませんでした。

私の最後の答えは:

.OrderByDescending(p => p.LowestPrice.HasValue).ThenBy(p => p.LowestPrice)

7

私の決定:

Array = _context.Products.OrderByDescending(p => p.Val ?? float.MinValue)

7

これは私が拡張メソッドを使用していて、アイテムが文字列であるため、私が思いついたものであり、したがって.HasValue

.OrderBy(f => f.SomeString == null).ThenBy(f => f.SomeString)

これは、メモリ内のLINQ 2オブジェクトで機能します。EFやDB ORMではテストしていません。


0

以下は、keySelectorの子プロパティでソートする場合にnullをチェックする拡張メソッドです。

public static IOrderedEnumerable<T> NullableOrderBy<T>(this IEnumerable<T> list, Func<T, object> parentKeySelector, Func<T, object> childKeySelector)
{
    return list.OrderBy(v => parentKeySelector(v) != null ? 0 : 1).ThenBy(childKeySelector);
}

そして単純にそれを次のように使用します:

var sortedList = list.NullableOrderBy(x => x.someObject, y => y.someObject?.someProperty);

0

ここに別の方法があります:

//Acsending
case "SUP_APPROVED_IND": qry =
                            qry.OrderBy(r => r.SUP_APPROVED_IND.Trim() == null).
                                    ThenBy(r => r.SUP_APPROVED_IND);

                            break;
//….
//Descending
case "SUP_APPROVED_IND": qry =
                            qry.OrderBy(r => r.SUP_APPROVED_IND.Trim() == null).
                                    ThenByDescending(r => r.SUP_APPROVED_IND); 

                            break;

SUP_APPROVED_IND is char(1) in Oracle db.

r.SUP_APPROVED_IND.Trim() == nullとして扱われることに注意してくださいtrim(SUP_APPROVED_IND) is nullOracle dbとに。

詳細はこちらをご覧ください:エンティティフレームワークでnull値を照会するにはどうすればよいですか?


0

別のオプション(このシナリオでは便利です):

ユーザーテーブルがあり、 ADName, LastName, FirstName

  • ユーザーはアルファベット順である必要があります
  • ADNameに基づいてFirst / LastNameも含まれていないが、User-Listの末尾にあるアカウント
  • IDが「0」のダミーユーザー(「選択なし」)常に最上位にする必要があります。

テーブルスキーマを変更し、並べ替えグループを定義する「SortIndex」列を追加しました。(5のギャップを残したので、後でグループを挿入できます)

ID | ADName |      First Name | LastName | SortIndex
0    No Selection  null         null     | 0
1    AD\jon        Jon          Doe      | 5
3    AD\Support    null         null     | 10     
4    AD\Accounting null         null     | 10
5    AD\ama        Amanda       Whatever | 5

これで、クエリに関しては次のようになります。

SELECT * FROM User order by SortIndex, LastName, FirstName, AdName;

メソッド式:

db.User.OrderBy(u => u.SortIndex).ThenBy(u => u.LastName).ThenBy(u => u.FirstName).ThenBy(u => u.AdName).ToList();

期待される結果が得られます:

ID | ADName |      First Name | LastName | SortIndex
0    No Selection  null         null     | 0
5    AD\ama        Amanda       Whatever | 5
1    AD\jon        Jon          Doe      | 5
4    AD\Accounting null         null     | 10
3    AD\Support    null         null     | 10     
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.