所以今天我遇到了一个有趣的问题。我们有一个返回IList的WCF Web服务。在我想对它进行排序之前,这并不是什么大不了的事。
结果是IList接口没有内置的排序方法。
我最终使用ArrayList.Adapter(list).Sort(new MyComparer())
方法来解决问题,但它对我来说似乎有点“贫民窟”。
我玩弄了一个扩展方法,也继承了IList并实现了我自己的Sort()方法以及转换为List,但这些看起来都不太优雅。
所以我的问题是,是否有人有一个优雅的解决方案来排序IList
答案 0 :(得分:61)
您可以使用LINQ:
using System.Linq;
IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.ToList();
答案 1 :(得分:55)
这个问题激励我撰写博客文章:http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
我认为,理想情况下,.NET Framework将包含一个接受IList&lt; T&gt;的静态排序方法,但下一个最好的方法是创建自己的扩展方法。创建一些允许您对IList&lt; T&gt;进行排序的方法并不难。和List&lt; T&gt;一样。作为奖励,您可以使用相同的技术重载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);
}
}
使用这些扩展程序,像对待List一样对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/
答案 2 :(得分:54)
如何使用LINQ To Objects为您排序?
假设您有IList<Car>
,并且该车有Engine
属性,我相信您可以按如下方式排序:
from c in list
orderby c.Engine
select c;
编辑:您需要快速在此处获得答案。由于我提出了与其他答案略有不同的语法,我将留下我的答案 - 但是,所提出的其他答案同样有效。
答案 3 :(得分:9)
你将不得不做我认为的事情(将其转换为更具体的类型)。
也许将它放入T列表中而不是ArrayList中,这样您就可以获得类型安全性和更多选项来实现比较器。
答案 4 :(得分:4)
@DavidMills接受的答案非常好,但我认为可以改进。首先,当框架已经包含静态方法ComparisonComparer<T>
时,不需要定义Comparer<T>.Create(Comparison<T>)
类。此方法可用于动态创建IComparison
。
此外,它会将IList<T>
投射到IList
,这可能会带来危险。在我看到的大多数情况下,实现List<T>
的{{1}}用于实现IList
,但这不能得到保证,并且会导致代码变弱。
最后,重载的IList<T>
方法有4个签名,只有2个签名实现。
List<T>.Sort()
List<T>.Sort()
List<T>.Sort(Comparison<T>)
List<T>.Sort(IComparer<T>)
以下类实现List<T>.Sort(Int32, Int32, IComparer<T>)
接口的所有4个List<T>.Sort()
签名:
IList<T>
用法:
using System;
using System.Collections.Generic;
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<T>(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>
接口,这也将起作用。
答案 5 :(得分:1)
将您的IList
转换为List<T>
或其他一些通用集合,然后您可以使用System.Linq
命名空间轻松查询/排序它(它将提供一堆扩展方法)
答案 6 :(得分:1)
在我寻找原始帖子中描述的确切问题的解决方案时找到了这个帖子。然而,没有一个答案完全符合我的情况。布罗迪的答案非常接近。以下是我发现的情况和解决方案。
我有两个由NHibernate返回的相同类型的IList,并将两个IList合并为一个,因此需要进行排序。
就像Brody说我在对象上实现了一个ICompare(ReportFormat),这是我的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
由于一维数组实现了接口System.Collections.Generic.IList<T>
,因此可以像原始IList一样使用该数组。
答案 7 :(得分: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();
}
}
}
答案 8 :(得分:1)
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));**
答案 9 :(得分: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附带的扩展方法的重新实现,作为普通的静态方法编写。不幸的是,它非常丑陋和冗长。
答案 10 :(得分:0)
在VS2008中,当我单击服务引用并选择“配置服务引用”时,可以选择客户端如何反序列化从服务返回的列表。
值得注意的是,我可以选择System.Array,System.Collections.ArrayList和System.Collections.Generic.List
答案 11 :(得分: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
答案 12 :(得分:0)
using System.Linq;
var yourList = SomeDAO.GetRandomThings();
yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );
那很漂亮!贫民区。
答案 13 :(得分: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 一个 乙 ç
答案 14 :(得分:0)
如果您问我,这看起来更加简单。这对我来说是完美的。
您可以使用Cast()将其更改为IList,然后使用OrderBy():
var ordered = theIList.Cast<T>().OrderBy(e => e);
WHERE T是类型,例如。 Model.Employee或Plugin.ContactService.Shared.Contact
然后,您可以使用for循环及其DONE。
ObservableCollection<Plugin.ContactService.Shared.Contact> ContactItems= new ObservableCollection<Contact>();
foreach (var item in ordered)
{
ContactItems.Add(item);
}