Move item up in IEnumerable

て烟熏妆下的殇ゞ 提交于 2019-12-22 10:07:19

问题


I have a need to move an item in an IEnumerable<> up, that is move one item above another. What is the simplest way to do this?

A similar question was asked here but I don't have a generic list only an IEnumerable<>: Generic List - moving an item within the list


回答1:


As @Brian commented the question is a little unclear as to what move an item in an IEnumerable<> up means.

If you want to reorder an IEnumerable for a single item then the code below should might be what you are looking for.

public static IEnumerable<T> MoveUp<T>(this IEnumerable<T> enumerable, int itemIndex)
{
    int i = 0;

    IEnumerator<T> enumerator = enumerable.GetEnumerator();
    while (enumerator.MoveNext())
    {
        i++;

        if (itemIndex.Equals(i))
        {
            T previous = enumerator.Current;

            if (enumerator.MoveNext())
            {
                yield return enumerator.Current;
            }

            yield return previous;

            break;
        }

        yield return enumerator.Current;
    }

    while (enumerator.MoveNext())
    {
        yield return enumerator.Current;
    }
}



回答2:


You can't. IEnumerable is only to iterate through some items, not for editing a list of items




回答3:


You can use the ToList() extension method and use the answer from the question you referenced. e.g.

var list = enumerable.ToList();
//do stuff from other answer, and then convert back to enumerable if you want
var reorderedEnumerable = list.AsEnumerable();



回答4:


I didn't find anything that would do what you want with IEnumerable<T>. Having developed similar stuff in the past for specific types of collections, list, arrays, etc, I felt it was time to take a better look at it. So I took a couple of minutes to write a generic version that could be applied to any IEnumerable<T>.

I did some basic testing and parameter checking but by no means consider them compreensive. Given that disclaimer, let's get to the code:

static class Enumerable {
    public static IEnumerable<T> MoveDown<T>(this IEnumerable<T> source, int index) {
        if (source == null) {
            throw new ArgumentNullException("source");
        }
        T[] array = source.ToArray();
        if (index == array.Length - 1) {
            return source;
        }
        return Swap<T>(array, index, index + 1);
    }

    public static IEnumerable<T> MoveDown<T>(this IEnumerable<T> source, T item) {
        if (source == null) {
            throw new ArgumentNullException("source");
        }
        T[] array = source.ToArray();
        int index = Array.FindIndex(array, i => i.Equals(item));
        if (index == -1) {
            throw new InvalidOperationException();
        }
        if (index == array.Length - 1) {
            return source;
        }
        return Swap<T>(array, index, index + 1);
    }

    public static IEnumerable<T> MoveUp<T>(this IEnumerable<T> source, int index) {
        if (source == null) {
            throw new ArgumentNullException("source");
        }
        T[] array = source.ToArray();
        if (index == 0) {
            return source;
        }
        return Swap<T>(array, index - 1, index);
    }

    public static IEnumerable<T> MoveUp<T>(this IEnumerable<T> source, T item) {
        if (source == null) {
            throw new ArgumentNullException("source");
        }
        T[] array = source.ToArray();
        int index = Array.FindIndex(array, i => i.Equals(item));
        if (index == -1) {
            throw new InvalidOperationException();
        }
        if (index == 0) {
            return source;
        }
        return Swap<T>(array, index - 1, index);
    }

    public static IEnumerable<T> Swap<T>(this IEnumerable<T> source, int firstIndex, int secondIndex) {
        if (source == null) {
            throw new ArgumentNullException("source");
        }
        T[] array = source.ToArray();
        return Swap<T>(array, firstIndex, secondIndex);
    }

    private static IEnumerable<T> Swap<T>(T[] array, int firstIndex, int secondIndex) {
        if (firstIndex < 0 || firstIndex >= array.Length) {
            throw new ArgumentOutOfRangeException("firstIndex");
        }
        if (secondIndex < 0 || secondIndex >= array.Length) {
            throw new ArgumentOutOfRangeException("secondIndex");
        }
        T tmp = array[firstIndex];
        array[firstIndex] = array[secondIndex];
        array[secondIndex] = tmp;
        return array;
    }

    public static IEnumerable<T> Swap<T>(this IEnumerable<T> source, T firstItem, T secondItem) {
        if (source == null) {
            throw new ArgumentNullException("source");
        }
        T[] array = source.ToArray();
        int firstIndex = Array.FindIndex(array, i => i.Equals(firstItem));
        int secondIndex = Array.FindIndex(array, i => i.Equals(secondItem));
        return Swap(array, firstIndex, secondIndex);
    }
}

As you can see, MoveUp and MoveDown are basically Swap operations. With MoveUp you swap positions with the previous element and with MoveDown you swap positions with the next element. Of course, that does not apply for moving up the first element or moving down the last element.

Running a quick test with the code below...

class Program {
    static void Main(string[] args) {
        int[] a = { 0, 2, 1, 3, 4 };
        string[] z = { "Zero", "Two", "One", "Three", "Four" };
        IEnumerable<int> b = Enumerable.Swap(a, 1, 2);
        WriteAll(b);
        IEnumerable<int> c = Enumerable.MoveDown(a, 1);
        WriteAll(c);
        IEnumerable<int> d = Enumerable.MoveUp(a, 2);
        WriteAll(d);
        IEnumerable<int> f = Enumerable.MoveUp(a, 0);
        WriteAll(f);
        IEnumerable<int> g = Enumerable.MoveDown(a, 4);
        WriteAll(g);
        IEnumerable<string> h = Enumerable.Swap(z, "Two", "One");
        WriteAll(h);
        var i = z.MoveDown("Two");
        WriteAll(i);
        var j = z.MoveUp("One");
        WriteAll(j);
        Console.WriteLine("Press any key to continue...");
        Console.Read();
    }

    private static void WriteAll<T>(IEnumerable<T> b) {
        foreach (var item in b) {
            Console.WriteLine(item);
        }
    }

... it looks like everything is working well.

I hope it serves at least as a starting point for you.




回答5:


I like this approach

    /// <summary>
/// Extension methods for <see cref="System.Collections.Generic.List{T}"/>
/// </summary>
public static class ListExtensions
{
    public static void MoveForward<T>(this List<T> list, Predicate<T> itemSelector, bool isLastToBeginning)
    {
        Ensure.ArgumentNotNull(list, "list");
        Ensure.ArgumentNotNull(itemSelector, "itemSelector");

        var currentIndex = list.FindIndex(itemSelector);

        // Copy the current item
        var item = list[currentIndex];

        bool isLast = list.Count - 1 == currentIndex;

        if (isLastToBeginning && isLast)
        {
            // Remove the item
            list.RemoveAt(currentIndex);

            // add the item to the beginning
            list.Insert(0, item);
        }
        else if (!isLast)
        {
            // Remove the item
            list.RemoveAt(currentIndex);

            // add the item at next index
            list.Insert(currentIndex + 1, item);
        }
    }

    public static void MoveBack<T>(this List<T> list, Predicate<T> itemSelector, bool isFirstToEnd)
    {
        Ensure.ArgumentNotNull(list, "list");
        Ensure.ArgumentNotNull(itemSelector, "itemSelector");

        var currentIndex = list.FindIndex(itemSelector);

        // Copy the current item
        var item = list[currentIndex];

        bool isFirst = 0 == currentIndex;

        if (isFirstToEnd && isFirst)
        {
            // Remove the item
            list.RemoveAt(currentIndex);

            // add the item to the end
            list.Add(item);             
        }
        else if (!isFirstToEnd)
        {
            // Remove the item
            list.RemoveAt(currentIndex);

            // add the item to previous index
            list.Insert(currentIndex - 1, item);
        }
    }
}


来源:https://stackoverflow.com/questions/2431971/move-item-up-in-ienumerable

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!