Programing

일반 목록-목록 내에서 항목 이동

crosscheck 2020. 6. 22. 07:59
반응형

일반 목록-목록 내에서 항목 이동


그래서 나는 일반적인 목록 oldIndexnewIndex값을 가지고 있습니다.

나는에있는 항목을 이동할 oldIndex에, newIndex... 단순히 가능한 한.

어떤 제안?

노트

항목은 항목 사이에 종료되어야 (newIndex - 1)하고 newIndex 이전 이 제거되었습니다.


"일반 목록"이라고 말했지만 List (T) 클래스 를 사용해야한다고 지정하지 않았 으므로 여기에 다른 내용이 있습니다.

ObservableCollection에 (T) 클래스는이 이동 방법을 정확하게 당신이 원하는 않습니다.

public void Move(int oldIndex, int newIndex)

그 아래에는 기본적으로 다음 과 같이 구현됩니다.

T item = base[oldIndex];
base.RemoveItem(oldIndex);
base.InsertItem(newIndex, item);

보시 다시피 다른 사람들이 제안한 스왑 방법은 본질적으로 ObservableCollection 이 자체 Move 메서드에서 수행하는 것입니다.

업데이트 2015-12-30 : .NET이 오픈 소스이므로 Reflector / ILSpy를 사용하지 않고도 corefx에서 MoveMoveItem 메서드 의 소스 코드를 직접 확인할 수 있습니다 .


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

나는이 질문이 오래 되었다는 것을 알고 있지만 자바 스크립트 코드 의이 응답을 C #에 적용했습니다. 그것이 도움이되기를 바랍니다.

 public static void Move<T>(this List<T> list, int oldIndex, int newIndex)
{

    // exit if possitions 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;
}

List <T> .Remove () 및 List <T> .RemoveAt ()는 제거중인 항목을 반환하지 않습니다.

따라서 이것을 사용해야합니다 :

var item = list[oldIndex];
list.RemoveAt(oldIndex);
list.Insert(newIndex, item);

항목 삽입 현재에 oldIndex에있을 newIndex다음 원래 인스턴스를 제거합니다.

list.Insert(newIndex, list[oldIndex]);
if (newIndex <= oldIndex) ++oldIndex;
list.RemoveAt(oldIndex);

삭제하려는 항목의 색인이 삽입으로 인해 변경 될 수 있다는 점을 고려해야합니다.


목록에서 항목을 이동하는 확장 방법을 만들었습니다.

항목을 목록 기존 색인 위치로 이동하기 때문에 기존 항목을 이동하는 경우 색인이 이동하지 않아야 합니다.

@Oliver가 아래 (항목의 끝으로 항목을 이동)를 참조하는 경우는 실제로 테스트에 실패하지만 의도적으로 설계된 것입니다. 목록 끝에 항목 을 삽입하려면을 호출하면 List<T>.Add됩니다. 이 인덱스 위치는 이동 전에 존재하지 않으므로 실패 list.Move(predicate, list.Count) 해야합니다 .

어떤 경우에, 나는 두 개의 추가 확장 방법, 만든 MoveToEndMoveToBeginning찾을 수있는 소스있는, 여기를 .

/// <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);
        };
    }
}

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.


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


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

참고URL : https://stackoverflow.com/questions/450233/generic-list-moving-an-item-within-the-list

반응형