1

I have a list class that implements IEnumerable<T>.
Type T is a complex class with a string member as unique identifier. But it's enough to take just int as element type for explanations.

I want to move multiple items one step to left.
Example:
Original list: 0, 1, 2, 3, 4, 5
Now all bold items (0,3,4) should be moved to left (as far as possible).
Result list: 0, 1, 3, 4, 2, 5

Is there a good algorithm to do that? Maybe just with LINQ.

Edit: Answers for a List<T> list are welcome. My class has similar methods. (Thanks for hint by TylerOhlsen.)
Edit2: One selected item should not pass another selected item.

9
  • 1
    That's not really "as far as possible", do you mean to just move left one position? Commented Nov 7, 2012 at 15:36
  • 1
    @lc. One step to the left, as far as possible (e.g. 0 can't move) Commented Nov 7, 2012 at 15:37
  • @lc. Element 0 is not moved left. That is what I meant to be "as far as possible". And in case item 1 would also be marked to be moved (beside item 0) then this move would be also ignored. Commented Nov 7, 2012 at 15:39
  • 1
    This one looks like could help... stackoverflow.com/questions/2431971/move-item-up-in-ienumerable Commented Nov 7, 2012 at 15:39
  • @Rawling wouldn't that yield a result like this: 0, 1, 3, 2, 4, 5? thersch do you want the list to look like this 0, 3, 4, 1, 2, 5 or 0, 1, 3, 4, 2, 5 (the one you provided). In the latter one why doesn't the 1 move? Commented Nov 7, 2012 at 15:44

4 Answers 4

3

This looks like it works:

public static IEnumerable<T> MoveSelectedLeft<T>(
    this IEnumerable<T> source,
    IEnumerable<int> indicesToMove /* must be in order! */)
{
    using (var itm = indicesToMove.GetEnumerator())
    {
        bool hasNextToMove = itm.MoveNext();
        int nextToMove = hasNextToMove ? itm.Current : -1;

        bool canMoveYet = false;
        T held = default(T);
        int currentIndex = 0;

        foreach (T t in source)
        {
            if (hasNextToMove && nextToMove == currentIndex)
            {
                hasNextToMove = itm.MoveNext();
                nextToMove = hasNextToMove ? itm.Current : -1;
                yield return t;
            }
            else
            {
                if (!canMoveYet)
                {
                    canMoveYet = true;
                }
                else
                {
                    yield return held;
                }
                held = t;
            }

            currentIndex++;
        }

        if (canMoveYet)
            yield return held;
    }
}

called as

foreach (int i in new[] { 0,1,2,3,4,5 }.MoveSelectedLeft(new[] { 0,3,4 }))
{
    Console.WriteLine(i);
}
Sign up to request clarification or add additional context in comments.

Comments

2

I didn't come up with a good way to use Linq, but here's a simple looping algorithm. If you can come up with a Sort function, that would be better. Or you could look at the Linq Zip method.

IList<int> myList = new List<int>(new[] {0, 1, 2, 3, 4, 5});
IList<int> moveLeftList = new List<int>(new[] {0, 1, 3, 4});

//Go through the original list in order and remove
// all items from the move left list until you reach
// the first item that is not going to be moved left.
//Items removed are already as far left as they can be
// so they do not need to be moved left and can therefore
// be safely removed from the list to be moved.
foreach (int item in myList)
{
    int index = moveLeftList.IndexOf(item);

    if (index >= 0)
        moveLeftList.RemoveAt(index);
    else
        break;
}

foreach (int item in moveLeftList)
{
    int index = myList.IndexOf(item);

    //Dont move left if it is the first item in the list or it is not in the list
    if (index <= 0)
        continue;

    //Swap with this item with the one to its left
    myList.RemoveAt(index);
    myList.Insert(index-1, item);
}

3 Comments

If your moveLeftList includes both 0 and 1, does this swap them?
@TylerOhlsen One selected item should not pass another selected item.
Edited to now handle that special case since that only occurs for the first and subsequent items in the list.
1

Here's a description of an algorithm. store the element directly to leftof your group of elements(in this case a 2) in a `temp variable.

starting at the leftmost element, move the elements to the left 1 by 1.

place the temp variable to the right of where the group now is.

If you're using a linked list, it can be better. you just remove the 2 from where it is, and insert it to the right of the group.

Comments

1

You should use the "Sort" function for this and provide a custom comparer.

Take a look at this example.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.