Generic List - moving an item within the list

前端 未结 10 579
后悔当初
后悔当初 2020-11-28 04:32

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

I want to move the item at oldIndex, to newIndex.

相关标签:
10条回答
  • 2020-11-28 04:57

    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.

    0 讨论(0)
  • 2020-11-28 05:00

    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);
            };
        }
    }
    
    0 讨论(0)
  • 2020-11-28 05:05

    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.

    0 讨论(0)
  • 2020-11-28 05:07

    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);
    
    0 讨论(0)
  • 2020-11-28 05:09

    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());

    0 讨论(0)
  • 2020-11-28 05:13
    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);
    
    0 讨论(0)
提交回复
热议问题