views:

1438

answers:

5

So I have a generic list, and an oldIndex and a newIndex value.

I want to move the item at oldIndex, to newIndex...as simply as possible.

Any suggestions?

Note

The item should be end up between the items at (newIndex - 1) and newIndex before it was removed.

A: 

I would expect either:

// Makes sure item is at newIndex after the operation
T item = list[oldIndex];
list.RemoveAt(oldIndex);
list.Insert(newIndex, item);

... or:

// Makes sure relative ordering of newIndex is preserved after the operation, 
// meaning that the item may actually be inserted at newIndex - 1 
T item = list[oldIndex];
list.RemoveAt(oldIndex);
newIndex = (newIndex > oldIndex ? newIndex - 1, newIndex)
list.Insert(newIndex, item);

... would do the trick, but I don't have VS on this machine to check.

Aaron Maenpaa
RemoveAt doesn't return the item and you have to be wary of the index shifting due the to removal of an item from the list.
Garry Shutler
@Garry You are correct. As for the index shifting, it really depends on whether you want the the item at newIndex after the move or whether you want to preserve the relative ordering of where newIndex was before the RemoveAt.
Aaron Maenpaa
If you don't that's really weird as the behaviour will differ depending on whether newIndex is less or greater than oldIndex. That's a bug waiting to happen imo.
Garry Shutler
+2  A: 
var item = list[oldIndex];

list.RemoveAt(oldIndex);

if (newIndex > oldIndex) newIndex--; 
// the actual index could have shifted due to the removal

list.Insert(newIndex, item);
Garry Shutler
Your solution breaks down if there are two copies of item in the list, with one occurring before oldIndex. You should use RemoveAt to make sure you get the right one.
Aaron Maenpaa
Indeed, sneaky edge case
Garry Shutler
@Garry, I'm sorry for deleting your comment on my other answer but since we don't care about where the item on the newIndex goes before the move, in this case, moving is as good as swapping the items.
bruno conde
+1  A: 

Something like this:

List<object> l;
l.Insert(newIndex, l[oldIndex]);
if(newIndex <= oldIndex) ++oldIndex;
l.RemoveAt(oldIndex);

EDIT: Taking in to account the index shift, hope its correct. (tks for the comments)

Megacan
Sorry I managed to rollback your answer instead of adding a comment. No idea how I managed that. I think I changed it back now.
Garry Shutler
However, you don't take into account that the index of the item you want to remove may change due to the insertion.
Garry Shutler
Yes, you are right. I was only half seeing the problem.
Megacan
+1  A: 

List<T>.Remove() and List<T>.RemoveAt() do not return the item that is being removed.

Therefore you have to use this:

var item = list[oldIndex];
list.RemoveAt(oldIndex);
list.Insert(newIndex, item);
M4N
+2  A: 

Simplest way:

list[newIndex] = list[oldIndex];
list.RemoveAt(oldIndex);

EDIT

The question isn't very clear ... Since we don't care where the list[newIndex] item goes I think the simplest way of doing this is as follows (with or without an extension method):

    public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
    {
        T aux = list[newIndex];
        list[newIndex] = list[oldIndex];
        list[oldIndex] = aux;
    }

This solution is the fastest because it doesn't involve list insertions/removals.

bruno conde
That will overwrite the item at newIndex, not insert.
Garry Shutler
True but that's not specified in the question ...
bruno conde
@Garry Isn't the end result going to be the same?
Ozgur Ozcitak
No, you'll end up losing the value at newIndex which wouldn't happen if you inserted.
Garry Shutler