it-swarm.com.de

Allgemeine Liste - Verschieben eines Elements in der Liste

Also habe ich eine generische Liste und einen oldIndex und einen newIndex Wert.

Ich möchte das Objekt unter oldIndex so einfach wie möglich nach newIndex verschieben.

Irgendwelche Vorschläge?

Hinweis

Der Gegenstand sollte zwischen den Gegenständen bei (newIndex - 1) Und newIndex stehen bevor er wurde entfernt.

137
Richard Everett

Ich weiß, dass Sie "generische Liste" gesagt haben, aber Sie haben nicht angegeben, dass Sie die Klasse List (T) verwenden müssen.

Die ObservableCollection (T) -Klasse hat eine Move-Methode , die genau das tut, was Sie wollen.

public void Move(int oldIndex, int newIndex)

Darunter ist im Grunde so implementiert.

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

Wie Sie sehen können, ist die von anderen vorgeschlagene Swap-Methode im Wesentlichen das, was die ObservableCollection in ihrer eigenen Move-Methode tut.

UPDATE 30.12.2015: Sie können den Quellcode für Move und MoveItem sehen Methoden in corefx jetzt für Sie, ohne Reflector/ILSpy zu verwenden, da .NET Open Source ist.

120
jpierson
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);
117
Garry Shutler

Ich weiß, dass diese Frage alt ist, aber ich habe [~ # ~] diese [~ # ~] angepasst Antwort von Javascript-Code auf C # Ich hoffe es hilft

 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;
}
9
Francisco

List <T> .Remove () und List <T> .RemoveAt () geben das zu entfernende Element nicht zurück.

Dazu musst du folgendes benutzen:

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

Fügen Sie das Element ein, das sich derzeit unter oldIndex befindet, um sich unter newIndex zu befinden, und entfernen Sie dann die ursprüngliche Instanz.

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

Sie müssen berücksichtigen, dass sich der Index des Elements, das Sie entfernen möchten, aufgrund des Einfügens ändern kann.

5
Megacan

Ich habe eine Erweiterungsmethode zum Verschieben von Elementen in einer Liste erstellt.

Ein Index sollte sich nicht verschieben, wenn wir ein vorhandenes Element verschieben, da wir ein Element an eine vorhandenes Indexposition in der Liste verschieben.

Der Edge-Fall, auf den @Oliver unten verweist (Verschieben eines Elements an das Ende der Liste), würde tatsächlich dazu führen, dass die Tests fehlschlagen. Dies ist jedoch beabsichtigt. Um ein neu Element am Ende der Liste einzufügen, rufen wir einfach List<T>.Add Auf. list.Move(predicate, list.Count) should schlägt fehl, da diese Indexposition vor dem Verschieben nicht existiert.

Auf jeden Fall habe ich zwei zusätzliche Erweiterungsmethoden erstellt, MoveToEnd und MoveToBeginning, deren Quelle sich hier befindet.

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

Ich würde entweder erwarten:

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

... oder:

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

... würde den Trick machen, aber ich habe kein VS auf dieser Maschine, um es zu überprüfen.

1
Aaron Maenpaa

Einfachster Weg:

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

EDIT

Die Frage ist nicht sehr klar ... Da es uns egal ist, wo das list[newIndex] item goes Ich denke, der einfachste Weg dies zu tun ist wie folgt (mit oder ohne Erweiterungsmethode):

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

Diese Lösung ist die schnellste, da keine Listeneinfügungen/-entfernungen erforderlich sind.

0
bruno conde