2008-08-19 93 views
68

因此,今天我遇到了一個有趣的問題。我們有一個返回IList的WCF Web服務。直到我想對它進行分類纔算真正的大事。在C中對IList進行排序#

原來,IList接口不具有內置的排序方法。

我結束了使用ArrayList.Adapter(list).Sort(new MyComparer())方法來解決問題,但它只是顯得有點「貧民窟」給我。

我玩弄寫了一個擴展方法,也從IList繼承和實現我自己的Sort()方法以及鑄造到列表,但沒有一個看起來過於優雅。

所以我的問題是,沒有任何人有一個優雅的解決排序一個IList

+0

爲什麼你會首先返回一個IList?從WCF服務? – DaeMoohn 2011-02-18 15:42:20

回答

51

如何使用LINQ to對象進行排序的嗎?

假設你有一個IList<Car>,而汽車有一個Engine財產,我相信你可以排序如下:

from c in list 
orderby c.Engine 
select c; 

編輯:您確實需要快速得到答案在這裏。正如我對其他答案的語法略有不同,我會留下我的答案 - 但是,其他答案同樣有效。

+0

它將創建一個新的枚舉值,在某些情況下這可能不合乎需要。根據我的知識,除了通過使用ArrayList.Adapter方法之外,不能通過接口就地對IList 進行排序。 – 2014-08-28 11:11:38

9

你將不得不做這樣的事情,我認爲(轉換成更具體的類型)。

也許把它放到T列表而不是ArrayList中,這樣你就可以獲得類型安全和更多選項來實現比較器。

2

將您IListList<T>或一些其他泛型集合,然後你可以很容易地查詢/排序使用System.Linq命名空間(它會提供一大堆的擴展方法),它

+6

`IList `實現`IEnumerable `,因此不需要轉換爲使用Linq操作。 – 2010-07-13 22:43:17

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; 
    } 
} 

Cast函數只是作爲普通靜態方法書寫的3.5擴展方法的重新實現。不幸的是這很醜陋而且冗長。

0

在VS2008中,當我點擊服務參考並選擇「配置服務參考」時,可以選擇客戶端如何反序列化服務返回的列表。

值得注意的是,我的System.Array,System.Collections.ArrayList和System.Collections.Generic.List

0

之間,選擇上找到一個很好的職位想我會分享。 Check it out HERE

基本上。

您可以創建下面的類和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); 
} 
} 

然後如果你有一個IList,你可以這樣排序。

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返回的相同類型的IList,並已將兩個IList出現在一箇中,因此需要進行排序。

像布羅迪說我實現上的對象(ReportFormat)的ICompare這是我的IList的類型:

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

我然後轉換合併的IList到相同類型的數組:

ReportFormat[] myReports = new ReportFormat[reports.Count]; //reports is the merged IList 

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

由於一維陣列實現了I:

陣列然後排序接口System.Collections.Generic.IList<T>,該陣列可以像原來的IList一樣使用。

+0

這是做到這一點的正確方法。 – user29964 2010-09-29 08:55:08

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 乙 甲 Ç

列表 甲 乙 Ç

IList的再次 甲 乙 Ç

+0

如果它真的是一個列表有效。在某些情況下,你有其他類型實現IList (例如,一個普通的數組),其中downcast不會工作。太糟糕了,Sort()方法不是IList 的擴展方法。 – Cygon 2012-01-05 13:32:03

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框架將包括接受一個I​​List <牛逼>一個靜態的排序方法,但未來最好事情就是創建你自己的擴展方法。創建一些方法並不難,因爲您可以像清單<T>那樣對IList <T>進行排序。作爲獎勵,您可以使用相同的技術重載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 `執行它,並且有一個靜態方法可以對任何` IList `通過檢查它是否實現了`ISortableList `,如果沒有,將它複製到一個數組,將其排序,清除IList `並重新添加項目。 – supercat 2012-09-28 23:32:22

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接受的答案是相當不錯,但我認爲它可以改進。首先,當框架已經包含一個靜態方法Comparer<T>.Create(Comparison<T>)時,沒有必要定義ComparisonComparer<T>類。這種方法可用於即時創建IComparison

此外,它將IList<T>轉換爲IList,這有潛在危險。在我看到的大多數情況下,實現IListList<T>在幕後用於實現IList<T>,但這不能保證,並且會導致代碼變得脆弱。

最後,超載的List<T>.Sort()方法有4個簽名,只有2個被實現。

  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()簽名:

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]; 
     } 
    } 
} 

用法:

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,這也可以工作。