2008-08-19 62 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,这也可以工作。