2008-08-19 23 views
68

私は今日興味深い問題に出くわしました。 IListを返すWCF Webサービスがあります。私がそれを並べ替えることを望むまでは、大したことではありません。C#でIListをソートする

は、IListインターフェイスは、ソート方法を内蔵しておりませんが判明。

私は問題を解決するためにArrayList.Adapter(list).Sort(new MyComparer())メソッドを使用して終了しますが、それはちょうど私には少し「ゲットー」を見えました。

私はIListを継承し、独自のSort()メソッドを実装し、Listにキャストする拡張メソッドを書きましたが、あまりにも上品ではありませんでした。

だから私の質問は、誰もがあなたは、私が(より具体的な形に変換)と思うような何かをする必要があるとしているのIList

+0

最初にIListを返すのはなぜですか? WCFサービスからですか? – DaeMoohn

答えて

51

どのようにあなたのためのソートするオブジェクトにLINQを使用してはどうですか?

は、あなたがIList<Car>を持っていると言うと、車はEngineプロパティを持っていた、私は次のように並べ替えることができ信じる:

from c in list 
orderby c.Engine 
select c; 

編集:あなたがここで回答を得るために迅速にする必要があります。私が他の答えと少し異なる構文を提示したので、私は答えを残します - しかし、提示された他の答えも同様に有効です。

+0

新しい列挙型を作成しますが、これはいくつかのシナリオでは望ましくないかもしれません。私の知る限りでは、ArrayList.Adapterメソッドを使用する以外は、IList をインタフェースでソートすることはできません。これを行う正しい方法は –

9

をソートするエレガントなソリューションを持っているんです。

おそらく、ArrayListではなくTのリストに入れて、型の安全性と比較関数の実装方法に関するオプションを得ることができます。

2

はあなたIListList<T>またはいくつかの他の一般的なコレクションに変換した後、あなたは簡単に並べ替えることが(それは拡張メソッドの束を供給します)System.Linq名前空間を使用してクエリ/でき

+6

'IList 'は 'IEnumerable 'を実装しているため、Linq演算を使用するために変換する必要はありません。 –

56

あなたは、LINQを使用することができます。

using System.Linq; 

IList<Foo> list = new List<Foo>(); 
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar); 
IList<Foo> sortedList = sortedEnum.ToList(); 
0

はここで強い型付けを使用した例です。それが必ずしも最良の方法であるかどうかは分かりません。

static void Main(string[] args) 
{ 
    IList list = new List<int>() { 1, 3, 2, 5, 4, 6, 9, 8, 7 }; 
    List<int> stronglyTypedList = new List<int>(Cast<int>(list)); 
    stronglyTypedList.Sort(); 
} 

private static IEnumerable<T> Cast<T>(IEnumerable list) 
{ 
    foreach (T item in list) 
    { 
     yield return item; 
    } 
} 

キャスト機能は、通常の静的メソッドとして記述されている3.5の拡張メソッドの再実装に過ぎません。それは残念なことに、かなり醜いと冗長です。

0

VS2008では、サービス参照をクリックして「サービス参照の設定」を選択すると、クライアントがサービスから返されたリストをどのように非直列化するかを選択するオプションがあります。

注目すべきことに、私はこの上で良い記事を発見のSystem.Array、System.Collections.ArrayListとSystem.Collections.Generic.List

0

の間で選択すると、私は共有したいと思ったことができます。 Check it out HERE

基本的には、

あなたがIListのを持っている場合はその後、あなたはこのようにそれを並べ替えることができます以下のクラスとしたIComparerクラス

public class Widget { 
    public string Name = string.Empty; 
    public int Size = 0; 

    public Widget(string name, int size) { 
    this.Name = name; 
    this.Size = size; 
} 
} 

public class WidgetNameSorter : IComparer<Widget> { 
    public int Compare(Widget x, Widget y) { 
     return x.Name.CompareTo(y.Name); 
} 
} 

public class WidgetSizeSorter : IComparer<Widget> { 
    public int Compare(Widget x, Widget y) { 
    return x.Size.CompareTo(y.Size); 
} 
} 

を作成することができます。

List<Widget> widgets = new List<Widget>(); 
widgets.Add(new Widget("Zeta", 6)); 
widgets.Add(new Widget("Beta", 3)); 
widgets.Add(new Widget("Alpha", 9)); 

widgets.Sort(new WidgetNameSorter()); 
widgets.Sort(new WidgetSizeSorter()); 

しかし、チェックアウトの詳細については、このサイト... Check it out HERE

0
using System.Linq; 

var yourList = SomeDAO.GetRandomThings(); 
yourList.ToList().Sort((thing, randomThing) => thing.CompareThisProperty.CompareTo(randomThing.CompareThisProperty)); 

かわいい!ゲットーです。

1

元の投稿に記載されている問題の解決方法を探しているうちに、このスレッドが見つかりました。しかし、私の状況は全く答えられませんでした。ブロディの答えはかなり近かった。ここに私が見つけた私の状況と解決策があります。

私はNHibernateから返された同じ型の2つのIListを持っており、2つのIListが1つになっているので、並べ替えが必要です。

ブロディは私のIListのタイプであるオブジェクト(ReportFormat)にICompare実施言ったように:私は、同じタイプの配列にマージするIListを変換

public class FormatCcdeSorter:IComparer<ReportFormat> 
    { 
     public int Compare(ReportFormat x, ReportFormat y) 
     { 
      return x.FormatCode.CompareTo(y.FormatCode); 
     } 
    } 

を:

ReportFormat[] myReports = new ReportFormat[reports.Count]; //reports is the merged IList 
一次元アレイは、Iを実装

Array.Sort(myReports, new FormatCodeSorter());//sorting using custom comparer 

ため:

は、配列を並べ替えますnterface System.Collections.Generic.IList<T>の場合、配列は元のIListと同じように使用できます。

+0

です。 – user29964

0

これは有効な解決策ですか?

 IList<string> ilist = new List<string>(); 
     ilist.Add("B"); 
     ilist.Add("A"); 
     ilist.Add("C"); 

     Console.WriteLine("IList"); 
     foreach (string val in ilist) 
      Console.WriteLine(val); 
     Console.WriteLine(); 

     List<string> list = (List<string>)ilist; 
     list.Sort(); 
     Console.WriteLine("List"); 
     foreach (string val in list) 
      Console.WriteLine(val); 
     Console.WriteLine(); 

     list = null; 

     Console.WriteLine("IList again"); 
     foreach (string val in ilist) 
      Console.WriteLine(val); 
     Console.WriteLine(); 

結果は次の通りであった: のIList B C

リスト B C

のIList再び B C

+0

本当にリストの場合は有効です。場合によっては、ダウンキャストが機能しないIList (たとえば、プレーンな配列)を実装する他の型があります。 Sort()メソッドがIList の拡張メソッドではないことも悪いことです。 – Cygon

1

ソーティンググリッドのための有用なこのメソッドはリストをソートします。プロパティ名に基づいています。例に従ってください。

List<MeuTeste> temp = new List<MeuTeste>(); 

    temp.Add(new MeuTeste(2, "ramster", DateTime.Now)); 
    temp.Add(new MeuTeste(1, "ball", DateTime.Now)); 
    temp.Add(new MeuTeste(8, "gimm", DateTime.Now)); 
    temp.Add(new MeuTeste(3, "dies", DateTime.Now)); 
    temp.Add(new MeuTeste(9, "random", DateTime.Now)); 
    temp.Add(new MeuTeste(5, "call", DateTime.Now)); 
    temp.Add(new MeuTeste(6, "simple", DateTime.Now)); 
    temp.Add(new MeuTeste(7, "silver", DateTime.Now)); 
    temp.Add(new MeuTeste(4, "inn", DateTime.Now)); 

    SortList(ref temp, SortDirection.Ascending, "MyProperty"); 

    private void SortList<T>(
    ref List<T> lista 
    , SortDirection sort 
    , string propertyToOrder) 
    { 
     if (!string.IsNullOrEmpty(propertyToOrder) 
     && lista != null 
     && lista.Count > 0) 
     { 
      Type t = lista[0].GetType(); 

      if (sort == SortDirection.Ascending) 
      { 
       lista = lista.OrderBy(
        a => t.InvokeMember(
         propertyToOrder 
         , System.Reflection.BindingFlags.GetProperty 
         , null 
         , a 
         , null 
        ) 
       ).ToList(); 
      } 
      else 
      { 
       lista = lista.OrderByDescending(
        a => t.InvokeMember(
         propertyToOrder 
         , System.Reflection.BindingFlags.GetProperty 
         , null 
         , a 
         , null 
        ) 
       ).ToList(); 
      } 
     } 
    } 
49

この質問は、ブログ記事を書くために私にインスピレーションを得た:http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

私は理想的には、.NET FrameworkがIListの<T>を受け入れ、静的なソート方法が含まれるであろう、と思いますが、次のベストあなた自身の拡張メソッドを作成することです。あなたがリスト<T>と同じように、IList <T>を並べ替えることのできる2つのメソッドを作成するのはそれほど難しくありません。ボーナスとして、同じテクニックを使用してLINQ OrderBy拡張メソッドをオーバーロードすることができます。そのため、List.Sort、IList.Sort、IEnumerable.OrderByのいずれを使用していても、まったく同じ構文を使用できます。これらの拡張子を持つ

public static class SortExtensions 
{ 
    // Sorts an IList<T> in place. 
    public static void Sort<T>(this IList<T> list, Comparison<T> comparison) 
    { 
     ArrayList.Adapter((IList)list).Sort(new ComparisonComparer<T>(comparison)); 
    } 

    // Convenience method on IEnumerable<T> to allow passing of a 
    // Comparison<T> delegate to the OrderBy method. 
    public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, Comparison<T> comparison) 
    { 
     return list.OrderBy(t => t, new ComparisonComparer<T>(comparison)); 
    } 
} 

// Wraps a generic Comparison<T> delegate in an IComparer to make it easy 
// to use a lambda expression for methods that take an IComparer or IComparer<T> 
public class ComparisonComparer<T> : IComparer<T>, IComparer 
{ 
    private readonly Comparison<T> _comparison; 

    public ComparisonComparer(Comparison<T> comparison) 
    { 
     _comparison = comparison; 
    } 

    public int Compare(T x, T y) 
    { 
     return _comparison(x, y); 
    } 

    public int Compare(object o1, object o2) 
    { 
     return _comparison((T)o1, (T)o2); 
    } 
} 

、あなたのようなソートあなたのIList希望リスト:

はポストでより多くの情報があります
IList<string> iList = new [] 
{ 
    "Carlton", "Alison", "Bob", "Eric", "David" 
}; 

// Use the custom extensions: 

// Sort in-place, by string length 
iList.Sort((s1, s2) => s1.Length.CompareTo(s2.Length)); 

// Or use OrderBy() 
IEnumerable<string> ordered = iList.OrderBy((s1, s2) => s1.Length.CompareTo(s2.Length)); 

http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

+0

正しいアプローチは本当に 'ISortableList 'インタフェースを提供していました(特定の比較関数を使ってリストの一部をソートするメソッドを持つ)、 'List 'を実装して、 'ISortableList 'が実装されているかどうかをチェックし、そうでない場合は配列にコピーし、ソートし、 'IList 'をクリアしてアイテムを再追加することで、IList ' – supercat

+3

素敵な答え!しかし、注意すべきことですが、このアプローチでは、 'IList list'が非汎用的な' IList'インタフェースにキャストできると仮定しています。 'IList 'インタフェースを実装している独自のクラスをコーディングする場合、非ジェネリックな 'IList'インタフェースも実装していることを確認してください。そうしないと、クラスはクラスキャスト例外で失敗します。 – sstan

0
try this **USE ORDER BY** : 

    public class Employee 
    { 
     public string Id { get; set; } 
     public string Name { get; set; } 
    } 

private static IList<Employee> GetItems() 
     { 
      List<Employee> lst = new List<Employee>(); 

      lst.Add(new Employee { Id = "1", Name = "Emp1" }); 
      lst.Add(new Employee { Id = "2", Name = "Emp2" }); 
      lst.Add(new Employee { Id = "7", Name = "Emp7" }); 
      lst.Add(new Employee { Id = "4", Name = "Emp4" }); 
      lst.Add(new Employee { Id = "5", Name = "Emp5" }); 
      lst.Add(new Employee { Id = "6", Name = "Emp6" }); 
      lst.Add(new Employee { Id = "3", Name = "Emp3" }); 

      return lst; 
     } 

**var lst = GetItems().AsEnumerable(); 

      var orderedLst = lst.OrderBy(t => t.Id).ToList(); 

      orderedLst.ForEach(emp => Console.WriteLine("Id - {0} Name -{1}", emp.Id, emp.Name));** 
4

@DavidMillsによって受け入れられた答えがありますかなり良いですが、私はそれが改善できると思います。 1つは、フレームワークにすでに静的メソッドComparer<T>.Create(Comparison<T>)が含まれている場合に、ComparisonComparer<T>クラスを定義する必要はありません。この方法は、即時にIComparisonを作成するために使用できます。

また、危険である可能性のあるIList<T>からIListにキャストします。私が見たほとんどの場合、を実装するために、IListを実装するList<T>が使用されていますが、これは保証されておらず、脆弱なコードにつながる可能性があります。

最後に、オーバーロードされたList<T>.Sort()メソッドは4つのシグネチャを持ち、そのうち2つだけが実装されています。

public static class IListExtensions 
{ 
    public static void Sort<T>(this IList<T> list) 
    { 
     if (list is List<T>) 
     { 
      ((List<T>)list).Sort(); 
     } 
     else 
     { 
      List<T> copy = new List<T>(list); 
      copy.Sort(); 
      Copy(copy, 0, list, 0, list.Count); 
     } 
    } 

    public static void Sort<T>(this IList<T> list, Comparison<T> comparison) 
    { 
     if (list is List<T>) 
     { 
      ((List<T>)list).Sort(comparison); 
     } 
     else 
     { 
      List<T> copy = new List<T>(list); 
      copy.Sort(comparison); 
      Copy(copy, 0, list, 0, list.Count); 
     } 
    } 

    public static void Sort<T>(this IList<T> list, IComparer<T> comparer) 
    { 
     if (list is List<T>) 
     { 
      ((List<T>)list).Sort(comparer); 
     } 
     else 
     { 
      List<T> copy = new List<T>(list); 
      copy.Sort(comparer); 
      Copy(copy, 0, list, 0, list.Count); 
     } 
    } 

    public static void Sort<T>(this IList<T> list, int index, int count, 
     IComparer<T> comparer) 
    { 
     if (list is List<T>) 
     { 
      ((List<T>)list).Sort(index, count, comparer); 
     } 
     else 
     { 
      List<T> range = new List<T>(count); 
      for (int i = 0; i < count; i++) 
      { 
       range.Add(list[index + i]); 
      } 
      range.Sort(comparer); 
      Copy(range, 0, list, index, count); 
     } 
    } 

    private static void Copy(IList<T> sourceList, int sourceIndex, 
     IList<T> destinationList, int destinationIndex, int count) 
    { 
     for (int i = 0; i < count; i++) 
     { 
      destinationList[destinationIndex + i] = sourceList[sourceIndex + i]; 
     } 
    } 
} 

  1. List<T>.Sort()
  2. List<T>.Sort(Comparison<T>)
  3. List<T>.Sort(IComparer<T>)
  4. List<T>.Sort(Int32, Int32, IComparer<T>)

以下のクラスは、IList<T>インターフェイスのすべての4 List<T>.Sort()署名を実装します

使用法:

class Foo 
{ 
    public int Bar; 

    public Foo(int bar) { this.Bar = bar; } 
} 

void TestSort() 
{ 
    IList<int> ints = new List<int>() { 1, 4, 5, 3, 2 }; 
    IList<Foo> foos = new List<Foo>() 
    { 
     new Foo(1), 
     new Foo(4), 
     new Foo(5), 
     new Foo(3), 
     new Foo(2), 
    }; 

    ints.Sort(); 
    foos.Sort((x, y) => Comparer<int>.Default.Compare(x.Bar, y.Bar)); 
} 

ここでの考え方は、可能な限り、ソート処理するための基礎となるList<T>の機能を利用することです。繰り返しになりますが、私が見た実装の多くはIList<T>です。基になるコレクションが異なるタイプの場合、入力リストの要素を持つList<T>の新しいインスタンスを作成することに代えて、それを使用してソートを行い、結果を入力リストにコピーし直します。これは入力リストがIListインターフェイスを実装していなくても機能します。

関連する問題