C#でリストの特定の要素の位置を変更する

あるリストに入ってる1つの要素の順序(位置)を変更します。

例えば、5番目の要素を3番目に移動したいなどの状況想定します。List クラスを使いますがこのようなメソッドは存在しません。

実装例

順序変更を List クラスの拡張メソッドとして実装したいと思います。

要素番号を指定して位置を変更する方法と、条件に一致した要素を指定した位置に変更する2種類を実装します。

using System;
using System.Collections.Generic;

public static class ListExtension
{
    /// <summary>
    /// 指定した位置の要素を指定したインデックス位置に変更します。
    /// </summary>
    public static void ChangeOrder<T>(this List<T> list, int oldIndex, int newIndex)
    {
        if (newIndex > list.Count - 1)
            throw new ArgumentOutOfRangeException(nameof(newIndex));

        if (oldIndex == newIndex) return;

        T item = list[oldIndex];
        list.RemoveAt(oldIndex);

        if (newIndex > list.Count)
        {
            list.Add(item);
        }
        else
        {
            list.Insert(newIndex, item);
        }
    }

    /// <summary>
    /// 指定した条件に一致した最初の要素を指定したインデックス位置へ移動します。
    /// </summary>
    public static void ChangeOrder<T>(this List<T> list, Predicate<T> condition, int newIndex)
    {
        if (newIndex > list.Count - 1)
            throw new ArgumentOutOfRangeException(nameof(newIndex));

        int oldIndex = list.FindIndex(condition);
        ChangeOrder(list, oldIndex, newIndex);
    }
}

使い方

シンプルな List<int> の場合、以下のように使用します。

var list = new List<int>() { 0, 1, 2, 3, 4 };

list.ChangeOrder(0, 4); // 0番目の要素を4番目に移動
// > 1 2 3 4 0
list.ChangeOrder(4, 1); // 4場番目の要素を1番目に移動
// > 1 0 2 3 4

プリミティブ型以外の自作クラスの場合以下のように使用します。

例えば以下のようなコンテナがあったとしてそれがリストに格納された場合の使い方です。

// サンプル用の自作クラス
public struct Sample
{
    public string Key { get; private set; }
    public Sample(string key) => Key = key;
    public static implicit operator Sample(string key) => new Sample(key);
}

// 使い方
var list = new List<Sample>() { "0", "1", "2", "3", "4" };

// キーが"0"の要素を4番目に移動
list.ChangeOrder(s => s.Key == "0", 4);
// > Key=1 2 3 4 0
// キーが"4"の要素を1番目に移動
list.ChangeOrder(s => s.Key == "4", 1);
// > Key=1 0 2 3 4

以上