2012-04-27 2 views
8

匿名オブジェクトで動作するようにLECDステートメントでOrderByを取得しようとしましたが、今は失敗しています。LINQ OrderByプロジェクションコンバーターを使用した匿名オブジェクト

私はすでに、これらのチェック:
Anonymous IComparer implementation
C# linq sort - quick way of instantiating IComparer
How to sort an array of object by a specific field in C#?

を私は別のアプローチをしようと数時間を過ごしたが、私は欠けている何かがなければなりません。

はのは、以下のクラスがあります言ってみましょう:

public class Product 
{ 
    public int Id {get; set;} 
    public string Name {get; set;} 
    public int Popularity {get; set;} 
    public decimal Price {get; set;} 
} 

そしてproductsは、これらのオブジェクトのリストです。

このLINQ文を匿名オブジェクトと一緒に使用するには、どのようにすればいいですか?
明確にするために、私はこれを別のやり方で行うことができますが、私はこの特定の例を動作させる方法を学ぶことに非常に関心があります。

var sortedProducts = products 
         .OrderBy(p => 
           new {p.Popularity, p.Price}, 
           [IComparer magic goes here]); 

ProjectionComparerの実装で可能なはずであると思われる:
http://code.google.com/p/edulinq/source/browse/src/Edulinq/ProjectionComparer.cs?r=0c583631b709679831c99df2646fc9adb781b2be

任意のアイデアはどのようにこれを行うには?

UPDATE:

私はこの上の迅速な性能試験でした - 標準orderby.thenby対匿名の比較演算のソリューションを、匿名のソリューションは、我々はとにかく期待しているかもしれないものはおそらくあるかなり遅いようです。 IComparer<T>上を行うには

var sortedProducts = products.OrderByDescending(p => p.Popularity) 
    .ThenBy(p => p.Price); 

:あなたは本当にあなたが同じように、組み合わせてOrerByとThenByを使用することができ、populartiy下降することにより、これらのオブジェクトを注文する匿名オブジェクトを必要とし、その後価格はありません

  numProd | Anon | chained orderby clauses 
     10 000 | 47 ms | 31 ms 
     100 000 | 468 ms | 234 ms 
     1 000 000| 5818 ms | 2387 ms 
     5 000 000| 29547 ms| 12105 ms 
+0

ご注文の基準は何ですか?あなたはそれが人気のものでなければならないと言っていますか? OrderByを人気につけて、次に価格で買ってみませんか? –

+0

@JamesMichaelHare - それは例えばどんな違いがあれば二次的要因として低価格、のが主な要因として高い人気を言ってみましょう。編集:私はこれを行うことができますが、私は匿名オブジェクトのアプローチがまったく動作するかどうか、もしそうなら、私はちょうど方法を理解できないのだろうか知っている。 –

+1

なぜOrderBy()で匿名オブジェクトを使用するのですか?なぜだけでなく: 'products.OrderByDescendingた(p => p.Popularity).ThenByた(p => p.Price)' –

答えて

7

あなたのオブジェクト上の他のMetricは))「の例で投げ」します

static class AnonymousComparer 
{ 
    public static IComparer<T> GetComparer<T>(T example, Comparison<T> comparison) 
    { 
     return new ComparerImpl<T>(comparison); 
    } 
    private class ComparerImpl<T> : IComparer<T> 
    { 
     private readonly Comparison<T> _comparison; 
     public ComparerImpl(Comparison<T> comparison) { _comparison = comparison; } 
     public int Compare(T x, T y) { return _comparison.Invoke(x, y); } 
    } 
} 

そしてこうしてそれを使用します。

var comparer = AnonymousComparer.GetComparer(
    new { Popularity = 0, Price = 0m }, 
    (a, b) => //comparison logic goes here 
    ); 

var sortedProducts = products 
    .OrderBy(p => 
     new { p.Popularity, p.Price }, 
     comparer); 

編集:私はちょうどあなたがにリンクされ、投影された比較ページをチェックアウトします。このアプローチでは、型推論のための "例"引数は必要ありません。しかし、インタフェースの代わりにデリゲートを作成するには、アプローチを変更する必要があります。ここでは、次のとおりです。

//adapted from http://code.google.com/p/edulinq/source/browse/src/Edulinq/ProjectionComparer.cs?r=0c583631b709679831c99df2646fc9adb781b2be 
static class AnonymousProjectionComparer 
{ 
    private class ProjectionComparer<TElement, TKey> : IComparer<TElement> 
    { 
     private readonly Func<TElement, TKey> keySelector; 
     private readonly Comparison<TKey> comparison; 

     internal ProjectionComparer(Func<TElement, TKey> keySelector, Comparison<TKey> comparison) 
     { 
      this.keySelector = keySelector; 
      this.comparison = comparison ?? Comparer<TKey>.Default.Compare; 
     } 

     public int Compare(TElement x, TElement y) 
     { 
      TKey keyX = keySelector(x); 
      TKey keyY = keySelector(y); 
      return comparison.Invoke(keyX, keyY); 
     } 
    } 

    public static IComparer<TElement> GetComparer<TElement, TKey>(Func<TElement, TKey> keySelector, Comparison<TKey> comparison) 
    { 
     return new ProjectionComparer<TElement, TKey>(keySelector, comparison); 
    } 
} 
+0

Brilliant!私は最初のバージョンを確認し、期待どおりに動作します。私は適応されたProjectionComparerもチェックして、例文によるキャストについてもっと学びます。包括的な答えをありがとうございました! –

4

匿名型では、ファクトリを使用してデリゲートから構造体を構築し、型推論を使用することをお勧めします(匿名型を推論せずに指定するのは苦痛です)。

あなたが発注のために純粋に匿名のオブジェクトを作成するためのパフォーマンスへの影響を測定したいかもしれないが、Phoogsの答えはその場でIComparer<T>を構築するためにComparison<T>デリゲートを使用するための良い方法を提供します。..

+0

上記を参照してください - それは自明であれば、私は助けなしにそれを行うことができたと思います。私は問題が別の方法で解決できることを知っています。 –

+0

@Joanna:理解し、ちょうどそれが[並べ替え/ ThenByを連鎖させることができることを知っての問題ではなかったことを確認したかったです。 Phoogには以下の素晴らしい解決策があります。 –

+0

私はいくつかの簡単なパフォーマンステストの結果で更新 - 匿名の比較子ソリューションが期待通りに遅くなります。それは知って良いです。 –

0

ない正確な答え..コメントは長すぎます:合理的な一般比較関数を作成するのは難しいです。

オブジェクトの比較関係が単一のプロパティによって十分に確立されている間に、複数のプロパティまたは2つのプロパティに対してもそのようなものはありません。私。これは非常に一般的な問題です。平らな面で点を注文しようとすると、2つの値(x、y)しかありませんが、(x1、y1)と答える方法はありません<(x2、y2)

ほとんどの場合、属性1、属性2、またはすべての属性を単一の値にマッピングすることによって(つまり、それらのすべてを単純に掛け合わせることによって)、注文を行うことになります。これらのアプローチは、簡単にLINQでの一般的な比較演算を必要とせずに表現されていますとの属性によって

  • 発注チェーンのOrderBy(ATTR1).OrderBy(ATTR2)....メトリックのOrderBy(ATTR1 * ATTR2)によって
  • 発注(またはあなたは比較のために供給し、デリゲートを使用していますIComparer<T>実装を行い、(型推論と同様のことをインスタンス化することができます
+1

私が興味を持っているのは、基本的にこのことの実装です:http://code.google.com/p/edulinq/source/browse/src/Edulinq/ProjectionComparer.cs?r=0c583631b709679831c99df2646fc9adb781b2be。私はこの権利を得れば残りはうまくいくだろうと思うが、私はこれにちょっとした助けが必要だ。 –

関連する問題