質問
そこで今日、興味深い問題に遭遇しました。IList を返す WCF Web サービスがあります。整理したいと思うまでは、それほど大したことではありませんでした。
IList インターフェイスにはsortメソッドが組み込まれていないことがわかりました。
結局使ったのは、 ArrayList.Adapter(list).Sort(new MyComparer())
問題を解決する方法ですが、私には少し「ゲットー」のように思えました。
拡張メソッドの作成、IList からの継承、独自の Sort() メソッドの実装、List へのキャストなどを試してみましたが、どれもあまりエレガントとは思えませんでした。
それで私の質問は、IListをソートするためのエレガントな解決策を持っている人はいますかということです
解決
LINQ To Objects を使用して並べ替えてみてはいかがでしょうか。
持っていると言ってください IList<Car>
, 、そして車には Engine
プロパティを使用すると、次のように並べ替えることができると思います。
from c in list
orderby c.Engine
select c;
編集:ここではすぐに答えを得る必要があります。他の回答とは若干異なる構文を提示したため、回答は残しておきますが、提示された他の回答も同様に有効です。
他のヒント
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> を受け入れる静的並べ替えメソッドが含まれると思いますが、次善の策は独自の拡張メソッドを作成することです。IList<T> を List<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);
}
}
これらの拡張機能を使用すると、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/
あなたは私が思うようなことをする必要があるでしょう(より具体的な型に変換する)。
おそらく、それを ArrayList ではなく T の List に取り込んで、型安全性と比較器の実装方法のオプションを増やします。
@DavidMillsによって受け入れられた回答は非常に優れていますが、改善できると思います。まず、定義する必要はありません。 ComparisonComparer<T>
フレームワークにすでに静的メソッドが含まれている場合のクラス Comparer<T>.Create(Comparison<T>)
. 。このメソッドを使用して、 IComparison
急いで。
また、それはキャストします IList<T>
に IList
それは危険な可能性を秘めています。私がこれまで見てきたほとんどのケースでは、 List<T>
実装するもの IList
実装するために舞台裏で使用されます 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>)
以下のクラスは 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>
入力リストの要素を使用して並べ替えを行い、結果を入力リストにコピーして戻します。これは、入力リストが IList
インターフェース。
元の投稿で説明されている正確な問題の解決策を探していたときに、このスレッドを見つけました。しかし、私の状況を完全に満たす答えはありませんでした。ブロディの答えはかなり近いものでした。これが私の状況とそれに対して私が見つけた解決策です。
NHibernate から返された同じ型の 2 つの IList があり、2 つの IList を 1 つにまとめたので、並べ替えが必要です。
Brody が言ったように、IList の型であるオブジェクト (ReportFormat) に ICompare を実装しました。
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
1次元配列でインターフェースを実装しているため、 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();
}
}
}
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));**
変換します IList
の中へ List<T>
または他の一般的なコレクションを使用すると、それを簡単にクエリ/並べ替えることができます。 System.Linq
名前空間 (多数の拡張メソッドを提供します)
以下は、より強力な型指定を使用した例です。ただし、それが必ずしも最良の方法であるかどうかはわかりません。
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 に付属する拡張メソッドを再実装したものです。残念ながら、それは非常に醜くて冗長です。
VS2008 では、サービス参照をクリックして [サービス参照の構成] を選択すると、クライアントがサービスから返されたリストを逆シリアル化する方法を選択するオプションがあります。
特に、System.Array、System.Collections.ArrayList、System.Collections.Generic.List のいずれかを選択できます。
using System.Linq;
var yourList = SomeDAO.GetRandomThings();
yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );
すごいですね!ゲットー。
これに関する良い投稿を見つけたので、共有したいと思いました。 ここでチェックしてください
基本的に。
次のクラスと 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());
しかし、詳細についてはこのサイトをチェックしてください... ここでチェックしてください
これは有効な解決策ですか?
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 A c
A B cをリストします
Ilist A B c