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?
The item should be end up between the items at (newIndex - 1)
and newIndex
before it was removed.
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);
Put into Extension methods they look like:
public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
{
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);
}
public static void Move<T>(this List<T> list, T item, int newIndex)
{
if (item != null)
{
var oldIndex = list.IndexOf(item);
if (oldIndex > -1)
{
list.RemoveAt(oldIndex);
if (newIndex > oldIndex) newIndex--;
// the actual index could have shifted due to the removal
list.Insert(newIndex, item);
}
}
}
This is how I implemented a move element extension method. It handles moving before/after and to the extremes for elements pretty well.
public static void MoveElement<T>(this IList<T> list, int fromIndex, int toIndex)
{
if (!fromIndex.InRange(0, list.Count - 1))
{
throw new ArgumentException("From index is invalid");
}
if (!toIndex.InRange(0, list.Count - 1))
{
throw new ArgumentException("To index is invalid");
}
if (fromIndex == toIndex) return;
var element = list[fromIndex];
if (fromIndex > toIndex)
{
list.RemoveAt(fromIndex);
list.Insert(toIndex, element);
}
else
{
list.Insert(toIndex + 1, element);
list.RemoveAt(fromIndex);
}
}
I know this question is old but I adapted THIS response of javascript code to C#. Hope it helps
public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
{
// exit if positions are equal or outside array
if ((oldIndex == newIndex) || (0 > oldIndex) || (oldIndex >= list.Count) || (0 > newIndex) ||
(newIndex >= list.Count)) return;
// local variables
var i = 0;
T tmp = list[oldIndex];
// move element down and shift other elements up
if (oldIndex < newIndex)
{
for (i = oldIndex; i < newIndex; i++)
{
list[i] = list[i + 1];
}
}
// move element up and shift other elements down
else
{
for (i = oldIndex; i > newIndex; i--)
{
list[i] = list[i - 1];
}
}
// put element from position 1 to destination
list[newIndex] = tmp;
}
Insert the item currently at oldIndex
to be at newIndex
and then remove the original instance.
list.Insert(newIndex, list[oldIndex]);
if (newIndex <= oldIndex) ++oldIndex;
list.RemoveAt(oldIndex);
You have to take into account that the index of the item you want to remove may change due to the insertion.
I created an extension method for moving items in a list.
An index should not shift if we are moving an existing item since we are moving an item to an existing index position in the list.
The edge case that @Oliver refers to below (moving an item to the end of the list) would actually cause the tests to fail, but this is by design. To insert a new item at the end of the list we would just call List<T>.Add
. list.Move(predicate, list.Count)
should fail since this index position does not exist before the move.
In any case, I've created two additional extension methods, MoveToEnd
and MoveToBeginning
, the source of which can be found here.
/// <summary>
/// Extension methods for <see cref="System.Collections.Generic.List{T}"/>
/// </summary>
public static class ListExtensions
{
/// <summary>
/// Moves the item matching the <paramref name="itemSelector"/> to the <paramref name="newIndex"/> in a list.
/// </summary>
public static void Move<T>(this List<T> list, Predicate<T> itemSelector, int newIndex)
{
Ensure.Argument.NotNull(list, "list");
Ensure.Argument.NotNull(itemSelector, "itemSelector");
Ensure.Argument.Is(newIndex >= 0, "New index must be greater than or equal to zero.");
var currentIndex = list.FindIndex(itemSelector);
Ensure.That<ArgumentException>(currentIndex >= 0, "No item was found that matches the specified selector.");
// Copy the current item
var item = list[currentIndex];
// Remove the item
list.RemoveAt(currentIndex);
// Finally add the item at the new index
list.Insert(newIndex, item);
}
}
[Subject(typeof(ListExtensions), "Move")]
public class List_Move
{
static List<int> list;
public class When_no_matching_item_is_found
{
static Exception exception;
Establish ctx = () => {
list = new List<int>();
};
Because of = ()
=> exception = Catch.Exception(() => list.Move(x => x == 10, 10));
It Should_throw_an_exception = ()
=> exception.ShouldBeOfType<ArgumentException>();
}
public class When_new_index_is_higher
{
Establish ctx = () => {
list = new List<int> { 1, 2, 3, 4, 5 };
};
Because of = ()
=> list.Move(x => x == 3, 4); // move 3 to end of list (index 4)
It Should_be_moved_to_the_specified_index = () =>
{
list[0].ShouldEqual(1);
list[1].ShouldEqual(2);
list[2].ShouldEqual(4);
list[3].ShouldEqual(5);
list[4].ShouldEqual(3);
};
}
public class When_new_index_is_lower
{
Establish ctx = () => {
list = new List<int> { 1, 2, 3, 4, 5 };
};
Because of = ()
=> list.Move(x => x == 4, 0); // move 4 to beginning of list (index 0)
It Should_be_moved_to_the_specified_index = () =>
{
list[0].ShouldEqual(4);
list[1].ShouldEqual(1);
list[2].ShouldEqual(2);
list[3].ShouldEqual(3);
list[4].ShouldEqual(5);
};
}
}
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);
Put into Extension methods they look like:
public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
{
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);
}
public static void Move<T>(this List<T> list, T item, int newIndex)
{
if (item != null)
{
var oldIndex = list.IndexOf(item);
if (oldIndex > -1)
{
list.RemoveAt(oldIndex);
if (newIndex > oldIndex) newIndex--;
// the actual index could have shifted due to the removal
list.Insert(newIndex, item);
}
}
}
Insert the item currently at oldIndex
to be at newIndex
and then remove the original instance.
list.Insert(newIndex, list[oldIndex]);
if (newIndex <= oldIndex) ++oldIndex;
list.RemoveAt(oldIndex);
You have to take into account that the index of the item you want to remove may change due to the insertion.
This is how I implemented a move element extension method. It handles moving before/after and to the extremes for elements pretty well.
public static void MoveElement<T>(this IList<T> list, int fromIndex, int toIndex)
{
if (!fromIndex.InRange(0, list.Count - 1))
{
throw new ArgumentException("From index is invalid");
}
if (!toIndex.InRange(0, list.Count - 1))
{
throw new ArgumentException("To index is invalid");
}
if (fromIndex == toIndex) return;
var element = list[fromIndex];
if (fromIndex > toIndex)
{
list.RemoveAt(fromIndex);
list.Insert(toIndex, element);
}
else
{
list.Insert(toIndex + 1, element);
list.RemoveAt(fromIndex);
}
}
Insert the item currently at oldIndex
to be at newIndex
and then remove the original instance.
list.Insert(newIndex, list[oldIndex]);
if (newIndex <= oldIndex) ++oldIndex;
list.RemoveAt(oldIndex);
You have to take into account that the index of the item you want to remove may change due to the insertion.
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);
I created an extension method for moving items in a list.
An index should not shift if we are moving an existing item since we are moving an item to an existing index position in the list.
The edge case that @Oliver refers to below (moving an item to the end of the list) would actually cause the tests to fail, but this is by design. To insert a new item at the end of the list we would just call List<T>.Add
. list.Move(predicate, list.Count)
should fail since this index position does not exist before the move.
In any case, I've created two additional extension methods, MoveToEnd
and MoveToBeginning
, the source of which can be found here.
/// <summary>
/// Extension methods for <see cref="System.Collections.Generic.List{T}"/>
/// </summary>
public static class ListExtensions
{
/// <summary>
/// Moves the item matching the <paramref name="itemSelector"/> to the <paramref name="newIndex"/> in a list.
/// </summary>
public static void Move<T>(this List<T> list, Predicate<T> itemSelector, int newIndex)
{
Ensure.Argument.NotNull(list, "list");
Ensure.Argument.NotNull(itemSelector, "itemSelector");
Ensure.Argument.Is(newIndex >= 0, "New index must be greater than or equal to zero.");
var currentIndex = list.FindIndex(itemSelector);
Ensure.That<ArgumentException>(currentIndex >= 0, "No item was found that matches the specified selector.");
// Copy the current item
var item = list[currentIndex];
// Remove the item
list.RemoveAt(currentIndex);
// Finally add the item at the new index
list.Insert(newIndex, item);
}
}
[Subject(typeof(ListExtensions), "Move")]
public class List_Move
{
static List<int> list;
public class When_no_matching_item_is_found
{
static Exception exception;
Establish ctx = () => {
list = new List<int>();
};
Because of = ()
=> exception = Catch.Exception(() => list.Move(x => x == 10, 10));
It Should_throw_an_exception = ()
=> exception.ShouldBeOfType<ArgumentException>();
}
public class When_new_index_is_higher
{
Establish ctx = () => {
list = new List<int> { 1, 2, 3, 4, 5 };
};
Because of = ()
=> list.Move(x => x == 3, 4); // move 3 to end of list (index 4)
It Should_be_moved_to_the_specified_index = () =>
{
list[0].ShouldEqual(1);
list[1].ShouldEqual(2);
list[2].ShouldEqual(4);
list[3].ShouldEqual(5);
list[4].ShouldEqual(3);
};
}
public class When_new_index_is_lower
{
Establish ctx = () => {
list = new List<int> { 1, 2, 3, 4, 5 };
};
Because of = ()
=> list.Move(x => x == 4, 0); // move 4 to beginning of list (index 0)
It Should_be_moved_to_the_specified_index = () =>
{
list[0].ShouldEqual(4);
list[1].ShouldEqual(1);
list[2].ShouldEqual(2);
list[3].ShouldEqual(3);
list[4].ShouldEqual(5);
};
}
}
Insert the item currently at oldIndex
to be at newIndex
and then remove the original instance.
list.Insert(newIndex, list[oldIndex]);
if (newIndex <= oldIndex) ++oldIndex;
list.RemoveAt(oldIndex);
You have to take into account that the index of the item you want to remove may change due to the insertion.
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.
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);
I know this question is old but I adapted THIS response of javascript code to C#. Hope it helps
public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
{
// exit if positions are equal or outside array
if ((oldIndex == newIndex) || (0 > oldIndex) || (oldIndex >= list.Count) || (0 > newIndex) ||
(newIndex >= list.Count)) return;
// local variables
var i = 0;
T tmp = list[oldIndex];
// move element down and shift other elements up
if (oldIndex < newIndex)
{
for (i = oldIndex; i < newIndex; i++)
{
list[i] = list[i + 1];
}
}
// move element up and shift other elements down
else
{
for (i = oldIndex; i > newIndex; i--)
{
list[i] = list[i - 1];
}
}
// put element from position 1 to destination
list[newIndex] = tmp;
}
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.
Is more simple guys just do this
public void MoveUp(object item,List Concepts){
int ind = Concepts.IndexOf(item.ToString());
if (ind != 0)
{
Concepts.RemoveAt(ind);
Concepts.Insert(ind-1,item.ToString());
obtenernombres();
NotifyPropertyChanged("Concepts");
}}
Do the same with MoveDown but change the if for "if (ind !=Concepts.Count())" and the Concepts.Insert(ind+1,item.ToString());
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.
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.
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.
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);
Put into Extension methods they look like:
public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
{
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);
}
public static void Move<T>(this List<T> list, T item, int newIndex)
{
if (item != null)
{
var oldIndex = list.IndexOf(item);
if (oldIndex > -1)
{
list.RemoveAt(oldIndex);
if (newIndex > oldIndex) newIndex--;
// the actual index could have shifted due to the removal
list.Insert(newIndex, item);
}
}
}
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);
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);
Put into Extension methods they look like:
public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
{
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);
}
public static void Move<T>(this List<T> list, T item, int newIndex)
{
if (item != null)
{
var oldIndex = list.IndexOf(item);
if (oldIndex > -1)
{
list.RemoveAt(oldIndex);
if (newIndex > oldIndex) newIndex--;
// the actual index could have shifted due to the removal
list.Insert(newIndex, item);
}
}
}
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.
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);
Is more simple guys just do this
public void MoveUp(object item,List Concepts){
int ind = Concepts.IndexOf(item.ToString());
if (ind != 0)
{
Concepts.RemoveAt(ind);
Concepts.Insert(ind-1,item.ToString());
obtenernombres();
NotifyPropertyChanged("Concepts");
}}
Do the same with MoveDown but change the if for "if (ind !=Concepts.Count())" and the Concepts.Insert(ind+1,item.ToString());
Source: Stackoverflow.com