[英]Sorting an IList in C#
所以我今天遇到了一個有趣的問題。 我們有一個返回 IList 的 WCF Web 服務。 在我想對它進行排序之前,這沒什么大不了的。
原來 IList 接口沒有內置排序方法。
我最終使用ArrayList.Adapter(list).Sort(new MyComparer())
方法來解決這個問題,但對我來說它似乎有點“貧民窟”。
我嘗試編寫擴展方法,也嘗試從 IList 繼承並實現我自己的 Sort() 方法以及轉換為 List,但這些方法似乎都不太優雅。
所以我的問題是,有沒有人有一個優雅的解決方案來對 IList 進行排序
您可以使用 LINQ:
using System.Linq;
IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.ToList();
這個問題啟發我寫了一篇博文: http : //blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
我認為,理想情況下,.NET Framework 將包含一個接受 IList<T> 的靜態排序方法,但接下來最好的事情是創建您自己的擴展方法。 創建一些方法來允許您像對 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));
}
// Sorts in IList<T> in place, when T is IComparable<T>
public static void Sort<T>(this IList<T> list) where T: IComparable<T>
{
Comparison<T> comparison = (l, r) => l.CompareTo(r);
Sort(list, 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/
使用 LINQ To Objects 為您排序怎么樣?
假設您有一個IList<Car>
,並且汽車有一個Engine
屬性,我相信您可以按如下方式排序:
from c in list
orderby c.Engine
select c;
編輯:您確實需要在這里快速獲得答案。 由於我提出了與其他答案略有不同的語法,因此我將留下我的答案——但是,所提出的其他答案同樣有效。
你將不得不做我認為類似的事情(將其轉換為更具體的類型)。
也許將其放入 T 的列表而不是 ArrayList 中,以便您獲得類型安全和更多關於如何實現比較器的選項。
@DavidMills 接受的答案非常好,但我認為可以改進。 一方面,當框架已經包含一個靜態方法Comparer<T>.Create(Comparison<T>)
時,不需要定義ComparisonComparer<T>
類。 此方法可用於動態創建IComparison
。
此外,它將IList<T>
強制轉換為IList
,這可能是危險的。 在我見過的大多數情況下,實現IList
List<T>
在幕后用於實現IList<T>
,但這不能保證並且可能導致脆弱的代碼。
最后,重載的List<T>.Sort()
方法有 4 個簽名,並且只實現了其中的 2 個。
List<T>.Sort()
List<T>.Sort(Comparison<T>)
List<T>.Sort(IComparer<T>)
List<T>.Sort(Int32, Int32, IComparer<T>)
下面的類為IList<T>
接口實現了所有 4 個List<T>.Sort()
簽名:
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>
的新實例,使用它進行排序,然后將結果復制回輸入列表。 即使輸入列表沒有實現IList
接口,這也將起作用。
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));**
在我尋找原始帖子中描述的確切問題的解決方案時找到了這個線程。 然而,沒有一個答案完全符合我的情況。 布羅迪的回答非常接近。 這是我的情況和我找到的解決方案。
我有兩個由 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
由於一維數組實現了接口System.Collections.Generic.IList<T>
,因此可以像原始 IList 一樣使用該數組。
此方法可用於網格排序,根據屬性名稱對列表進行排序。 按照這個例子。
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();
}
}
}
using System.Linq;
var yourList = SomeDAO.GetRandomThings();
yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );
這很漂亮!貧民窟。
這是使用更強類型的示例。 不確定這是否一定是最好的方法。
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 附帶的擴展方法的重新實現。 不幸的是,它非常丑陋和冗長。
這是一個有效的解決方案嗎?
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 BAC
列出ABC
我再次列出ABC
找到了一個很好的帖子,並認為我會分享。 在這里查看
基本上。
您可以創建以下類和 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());
但是請查看此站點以獲取更多信息...查看此處
如果你問我,這看起來更簡單。 這對我來說非常有效。
您可以使用 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);
}
在 VS2008 中,當我單擊服務引用並選擇“配置服務引用”時,有一個選項可以選擇客戶端如何反序列化從服務返回的列表。
值得注意的是,我可以在 System.Array、System.Collections.ArrayList 和 System.Collections.Generic.List 之間進行選擇
將您的IList
轉換為List<T>
或其他一些通用集合,然后您可以使用System.Linq
命名空間輕松查詢/排序它(它將提供一堆擴展方法)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.