Sort
LINQソリューションを求めていることは承知していますが、この状況でLINQを使用するのは複雑なようです。特に、カラムも調整したい場合はそうです。forループとインデックスを使用する単純な古いアプローチをお勧めします。ソート操作をインプレースで実行し、新しいリストを作成しません。
再利用できるようにするために、IList
インターフェイスの拡張メソッドとして作成します。これにより、配列との互換性も確保されます。
Sort
汎用的にするには、列にアクセスするための何らかの方法が必要です。インターフェイスを介してこの列を公開すると、ソリューションがこのインターフェイスを実装するクラスに制限されます。したがって、私はあなたが代理人として渡さなければならないアクセサーを選びました。Sort
たとえば、列に別の名前がある場合にも機能Order
します。
public static class ListExtensions
{
public static void MoveItem<T>(this IList<T> list, int fromIndex, int toIndex,
Func<T, int> getSortKey, Action<T, int> setSortKey)
{
T temp = list[fromIndex];
int lastSortKey = getSortKey(temp);
setSortKey(temp, getSortKey(list[toIndex]));
if (fromIndex > toIndex) { // Move towards beginning of list (upwards).
for (int i = fromIndex; i > toIndex; i--) {
list[i] = list[i - 1];
int nextSortKey = getSortKey(list[i]);
setSortKey(list[i], lastSortKey);
lastSortKey = nextSortKey;
}
} else if (fromIndex < toIndex) { // Move towards end of list (downwards).
for (int i = fromIndex; i < toIndex; i++) {
list[i] = list[i + 1];
int nextSortKey = getSortKey(list[i]);
setSortKey(list[i], lastSortKey);
lastSortKey = nextSortKey;
}
}
list[toIndex] = temp;
}
}
このような方法を使用できます
list.MoveItem(3, 1, x => x.Sort, (x, i) => x.Sort = i);
ソート値ではなく、リストインデックスを渡す必要があることに注意してください。
これが私がテストに使用したクラスです。ローカルウィンドウで結果を調べるには、2つのテストメソッドの最後にブレークポイントを設定するだけです。クラスを右クリックし、[Test
静的メソッドの呼び出し]を選択して、クラスビューでテストを開始します。
public class SomeItem
{
public int Sort { get; set; }
public string Value { get; set; }
public override string ToString()
{
return String.Format("Sort = {0}, Value = {1}", Sort, Value);
}
}
public static class Test
{
public static void MoveUp()
{
List<SomeItem> list = InitializeList();
list.MoveItem(3, 1, x => x.Sort, (x, i) => x.Sort = i);
}
public static void MoveDown()
{
List<SomeItem> list = InitializeList();
list.MoveItem(1, 3, x => x.Sort, (x, i) => x.Sort = i);
}
private static List<SomeItem> InitializeList()
{
return new List<SomeItem> {
new SomeItem{ Sort = 1, Value = "foo1" },
new SomeItem{ Sort = 2, Value = "foo2" },
new SomeItem{ Sort = 3, Value = "foo3" },
new SomeItem{ Sort = 4, Value = "foo4" },
new SomeItem{ Sort = 5, Value = "foo5" }
};
}
}
アップデート
ソートキーの調整に関する注意:ソートキーが順番に並んでいて一意である場合、上記の解決策はうまく機能します。これが常に当てはまるとは限らない場合、より堅牢な解決策は、ソートキーをリストインデックスと等しく設定するだけで、リストをDBに保存する前にソートキーを調整することです。MoveItem
これにより、メソッドが簡略化されます。
public static void MoveItem<T>(this IList<T> list, int fromIndex, int toIndex)
{
T temp = list[fromIndex];
if (fromIndex > toIndex) { // Move towards beginning of list (upwards).
for (int i = fromIndex; i > toIndex; i--) {
list[i] = list[i - 1];
}
} else if (fromIndex < toIndex) { // Move towards end of list (downwards).
for (int i = fromIndex; i < toIndex; i++) {
list[i] = list[i + 1];
}
}
list[toIndex] = temp;
}
public static void FixSortKeys<T>(this IList<T> list, Action<T, int> setSortKey)
{
for (int i = 0; i < list.Count; i++) {
setSortKey(list[i], i);
}
}