2016-06-22 8 views
2

私は問題の簡略化を作成しました。私は、フィルタオブジェクトをunorder可能性がどこで私は何があるだろうということを理解していないなぜフィルタリング後にIOrderedEnumerableが順序を保持しないのですか

IOrderedEnumerable<int> tmp = new List<int>().OrderBy(x => x); 
//Error Cannot Implicitly conver IEnumerable<int> To IOrderedEnumerable<int> 
tmp = tmp.Where(x => x > 1); 

に可能性を持っている必要がありながら

これはコンパイルされません適用し、なぜ私は思ったんだけど、IEnumerableを注文しましたlinqをいくつかのDBプロバイダに使用するなどのIQueryableから実行命令を受け取った場合、実行順序がわかります。

しかし、Linq To Objectを扱う場合、あなたのオブジェクトの順序を決めるシナリオは何か、あるいはこれはなぜ実装されなかったのでしょうか?

EDIT

は私が正しく問題ではないこと、これを注文する方法を理解します。私の質問は設計上の問題です。 linqからオブジェクトへのフィルタは、与えられた列挙型と適用フィルタリングを列挙する必要があります。だから、私たちはIOrderedEnumerableの代わりにIEnumerableしか返すことができないのはなぜですか?これはuserfulだろうときでsenarioを明確にするために

EDIT

。私はコード内の条件に基づいてクエリを構築していますが、可能な限り多くのコードを再利用したいと考えています。

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 

:私はそれが元の秩序状態にあるであろうにもかかわらず

+7

それはいけない - 絶対に罰金されるべきであること。あなたがそうでないことを観察していると言っているのであれば、[mcve]を提供してください。一般的には、注文する前にフィルタリングすることをお勧めします...無視しようとしているアイテムの読み込みをどうして迷うのですか? –

+3

'IOrderedEnumerable 'ではないかもしれませんが、まだ注文されていますか?そうでなければ見ていますか? –

+2

トピックをオフにしたかもしれませんが、なぜソート後に「どこで」ですか?より小さなリストで並べ替えが高速になります。 – Leon

答えて

12

ルネの答えは正しいのですが、いくつかの追加の説明を使用することができます。

IOrderedEnumerable<T>は、「これは注文された配列です」という意味ではありません。これは、「これは注文操作がに適用されたシーケンスであり、追加の注文要件を課すためにThenByでこれを実行することができます。「

Whereの結果は、あなたがThenByとそれをフォローアップすることはできませんので、あなたはIOrderedEnumerable<T>が必要とされているコンテキストでそれを使用することはできません。

は意味をなさない?

をしかし、もちろんの、他の人とあなたははほとんどは、常に最初にして、フィルタリング順序付けをしたい、と述べている。あなたはただ捨てるしようとしていることを順番にアイテムを入れて時間を費やしていないこの方法。

クールでありますあなたが注文してからフィルターをかけなければならない時はe回。たとえば、「女性が歌ったトップテンの歌」と「女性が歌ったトップ10の歌」というクエリは、潜在的に非常に異なっています。最初の曲はソングを並べ替える - >トップテンを取る - >フィルターを適用する。 2番目はフィルタを適用する - >曲をソートする - >トップテンを取る。

+0

それは理にかなっていますが、Wh​​ereからIOrderedEnumerableを返すことができないのですが、元のEnumerableが最初に順序付けされている場合、どこに依然として順序を保持する必要があるのでしょうか –

+0

'Where'を'IEnumerable 'と 'Where'は静的に型付けされています。 –

+0

@ johnny5:それは注文を保持しますが、別の 'IOrderedEnumerable 'を返しません。これは、入力と同じ順序を持つ 'IEnumerable 'を返します。なぜfoo.OrderBy(...)をしたいのですか?(...)。ThenBy(...) '?それはあなたが購入するすべてだからです... –

5

Where()の署名がこれです。この順序を変更しなければならないところ、私は、しかし、追加を適用した後、OrderedEnumerableを返す機能を持ちますしたがって、このメソッドは最初の引数としてIEnumerable<int>をとります。 OrderByから返されたIOrderedEnumerable<int>IEnumerable<int>を実装しています。これは問題ありません。

ご覧のとおり、WhereIOrderedEnumerable<int>ではなくIEnumerable<int>を返します。そして、これはお互いにキャストすることはできません。

とにかく、そのシーケンスのオブジェクトは、と同じの順番になります。だから、ちょうどこの

IEnumerable<int> tmp = new List<int>().OrderBy(x => x).Where(x => x > 1); 

のようにそれを行うと、あなたが期待されるシーケンスを得ることができます。

しかし、もちろん、あなたは(パフォーマンス上の理由のために)あなたのオブジェクト最初をフィルタリングし、ソートする少数のオブジェクトがある場合、その後にそれらを並べ替える必要があります。

IOrderedEnumerable<int> tmp = new List<int>().Where(x => x > 1).OrderBy(x => x); 
2

tmp変数の型はIOrderedEnumerableです。

Where()は、戻り値の型と同じような関数で、その戻り値の型はIEnumerableです。 IEnumerableIOrderedEnumerableは同じではありません。

は、だから、これを行うと:あなたはIOrderedEnumerableあるtmp変数に、IEnuemrableあるWhere()関数呼び出しの結果を代入しようとしている

tmp = tmp.Where(x => x > 1); 

。それらは直接互換性がなく、暗黙的なキャストはないので、コンパイラはエラーを送信します。

tmp変数の型があまりにも限定的であるという問題があります。このコードは意志すべての作業、IEnumerableから

IEnumerable<int> tmp = new List<int>().OrderBy(x => x); 
tmp = tmp.Where(x => x > 1); 

IOrderedEnumerableため継承:あなたは自分のtmp変数で少し具体的であることによって、このすべての作業を行います1つの簡単な変更を行うことができます。後でThenBy()に電話したくない場合は、tmp変数を後で使用する能力を失うことなく、まったく同じ結果が得られます。

IOrderedEnumerable<int> tmp = new List<int>().OrderBy(x => x); 
tmp = tmp.Where(x => x > 1).OrderBy(x => x); 

をそして再び、最も例(すべてではないが、ほとんどの)中で、あなたのフィルタリングを取得したい:あなた本当にIOrderedEnumerableが必要な場合は

、いつでももう一度.OrderBy(x => x)を呼び出すことができます並べ替えを開始する前に言い換えれば、これはさらに良いです:

var tmp = new List<int>().Where(x => x > 1).OrderBy(x => x); 
+0

なぜこれは私の質問をコンパイルしないのsymanticsを理解していますなぜ注文された列挙型その順番は –

+0

です。もう一度答えを確認してください。私はあなたを助けるかもしれない底に何かを加えました。 –

+0

私は、条件に基づいてビルドクエリを動作させる内部関数を持っています。その前に、列挙型が順序付けされている必要があります。次にlinqsのみがその実装に組み込まれていますが、ユーザーは任意のタイプの関数 –

1

はなぜこれが実装されていませんでしたか?

LINQデザイナーは、実装、テスト、ドキュメントなどの作業が潜在的な使用例に比べて十分ではないと判断したと考えられます。実際には、私が最初に聞いたのはあなたです。

しかし、それがあなたにとって大事な場合は、その欠けている機能を自分で追加することができます(@Jon Skeet MoreLINQ拡張ライブラリに似ています)。例えば、このような何か:

namespace MyLinq 
{ 
    public static class Extensions 
    { 
     public static IOrderedEnumerable<T> Where<T>(this IOrderedEnumerable<T> source, Func<T, bool> predicate) 
     { 
      return new WhereOrderedEnumerable<T>(source, predicate); 
     } 

     class WhereOrderedEnumerable<T> : IOrderedEnumerable<T> 
     { 
      readonly IOrderedEnumerable<T> source; 
      readonly Func<T, bool> predicate; 
      public WhereOrderedEnumerable(IOrderedEnumerable<T> source, Func<T, bool> predicate) 
      { 
       if (source == null) throw new ArgumentNullException(nameof(source)); 
       if (predicate == null) throw new ArgumentNullException(nameof(predicate)); 
       this.source = source; 
       this.predicate = predicate; 
      } 
      public IOrderedEnumerable<T> CreateOrderedEnumerable<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer, bool descending) => 
       new WhereOrderedEnumerable<T>(source.CreateOrderedEnumerable(keySelector, comparer, descending), predicate); 
      public IEnumerator<T> GetEnumerator() => Enumerable.Where(source, predicate).GetEnumerator(); 
      IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 
     } 
    } 
} 

と行動にそれを置く:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using MyLinq; 

var test = Enumerable.Range(0, 100) 
    .Select(n => new { Foo = 1 + (n/20), Bar = 1 + n }) 
    .OrderByDescending(e => e.Foo) 
    .Where(e => (e.Bar % 2) == 0) 
    .ThenByDescending(e => e.Bar) // Note this compiles:) 
    .ToList(); 
関連する問題