tags:

views:

202

answers:

4

Hi

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<>: http://stackoverflow.com/questions/450233/generic-list-moving-an-item-within-the-list

+1  A: 

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();
tmont
Or perhaps `enumerable.OrderBy(e => e)` would do the trick ;-)
Steven
+1  A: 

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;
    }
}
Kane
This is close to what I was looking for. Thank
Nina
+1  A: 

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

remi bourgarel
A: 

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.

Alfred Myers