Verschieben Sie ein Array-Element von einer Array-Position zur anderen

522

Es fällt mir schwer herauszufinden, wie man ein Array-Element verschiebt. Zum Beispiel, wenn Folgendes gegeben ist:

var arr = [ 'a', 'b', 'c', 'd', 'e'];

Wie kann ich eine Funktion schreiben, um sie 'd'vorher zu verschieben 'b'?

Oder 'a'danach 'c'?

Nach dem Verschieben sollten die Indizes der übrigen Elemente aktualisiert werden. Dies bedeutet, dass im ersten Beispiel nach der Bewegung arr [0] = 'a', arr [1] = 'd' arr [2] = 'b', arr [3] = 'c', arr [4] = 'e'

Das scheint ziemlich einfach zu sein, aber ich kann meinen Kopf nicht darum wickeln.

Mark Brown
quelle
3
Jalal
mit ES6const changeValuePosition = (arr, init, target) => {[arr[init],arr[target]] = [arr[target],arr[init]]; return arr}
muhsalaa
Das tauscht einfach die Elemente bei initund aus target.
Matt F.

Antworten:

671

Wenn Sie eine Version auf npm möchten, ist Array-Move dieser Antwort am nächsten, obwohl es nicht dieselbe Implementierung ist. Weitere Informationen finden Sie im Abschnitt zur Verwendung. Die vorherige Version dieser Antwort (die Array.prototype.move geändert hat) finden Sie auf npm unter array.prototype.move .


Ich hatte ziemlich gute Erfolge mit dieser Funktion:

function array_move(arr, old_index, new_index) {
    if (new_index >= arr.length) {
        var k = new_index - arr.length + 1;
        while (k--) {
            arr.push(undefined);
        }
    }
    arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
    return arr; // for testing
};

// returns [2, 1, 3]
console.log(array_move([1, 2, 3], 0, 1)); 

Beachten Sie, dass der letzte returnnur zu Testzwecken dient: spliceFührt Operationen am Array direkt aus, sodass eine Rückgabe nicht erforderlich ist. In der Erweiterung ist dies moveeine In-Place-Operation. Wenn Sie dies vermeiden und eine Kopie zurückgeben möchten, verwenden Sie slice.

Durch den Code gehen:

  1. Wenn new_indexes größer als die Länge des Arrays ist, möchten wir (nehme ich an) das Array richtig mit neuen undefineds auffüllen. Dieses kleine Snippet behandelt dies, indem es undefinedauf das Array drückt, bis wir die richtige Länge haben.
  2. Dann arr.splice(old_index, 1)[0]spleißen wir das alte Element aus. spliceGibt das Element zurück, das herausgespleißt wurde, aber es befindet sich in einem Array. In unserem obigen Beispiel war dies [1]. Also nehmen wir den ersten Index dieses Arrays, um den Rohwert 1dort zu erhalten.
  3. Dann splicefügen wir dieses Element an der Stelle des neuen Index ein. Da wir das Array oben mit if aufgefüllt haben new_index > arr.length, wird es wahrscheinlich an der richtigen Stelle angezeigt, es sei denn, sie haben etwas Seltsames getan, wie das Übergeben einer negativen Zahl.

Eine schickere Version, um negative Indizes zu berücksichtigen:

function array_move(arr, old_index, new_index) {
    while (old_index < 0) {
        old_index += arr.length;
    }
    while (new_index < 0) {
        new_index += arr.length;
    }
    if (new_index >= arr.length) {
        var k = new_index - arr.length + 1;
        while (k--) {
            arr.push(undefined);
        }
    }
    arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
    return arr; // for testing purposes
};
    
// returns [1, 3, 2]
console.log(array_move([1, 2, 3], -1, -2));

Was Dinge wie array_move([1, 2, 3], -1, -2)richtig berücksichtigen sollte (verschieben Sie das letzte Element auf den vorletzten Platz). Ergebnis dafür sollte sein [1, 3, 2].

So oder so, in Ihrer ursprünglichen Frage, würden Sie tun , array_move(arr, 0, 2)für anach c. Für dvorher bwürden Sie tun array_move(arr, 3, 1).

Reid
quelle
19
Das funktioniert perfekt! Und Ihre Erklärung ist sehr klar. Vielen Dank, dass Sie sich die Zeit genommen haben, dies aufzuschreiben.
Mark Brown
16
Sie sollten Objekt- und Array-Prototypen nicht manipulieren, da dies zu Problemen beim Iterieren von Elementen führt.
Burak Emre
9
@ Burakemre: Ich denke, dass die Schlussfolgerung nicht so klar erreicht wird. Die meisten guten JS-Programmierer (und die beliebtesten Bibliotheken) verwenden eine .hasOwnPropertyPrüfung, wenn sie mit Dingen wie for..in iterieren, insbesondere mit Bibliotheken wie Prototype und MooTools, die Prototypen modifizieren. Wie auch immer, ich hatte nicht das Gefühl, dass dies in einem relativ begrenzten Beispiel wie diesem ein besonders wichtiges Thema ist, und es gibt eine nette Spaltung in der Community darüber, ob eine Modifikation des Prototyps eine gute Idee ist oder nicht. Normalerweise sind Iterationsprobleme jedoch das geringste Problem.
Reid
3
In Schritt 1 ist die Schleife nicht erforderlich. Sie können sie einfach this[new_index] = undefined;innerhalb des ifBlocks verwenden. Da Javascript-Arrays spärlich sind, wird die Array-Größe um den new_index erweitert, damit das .splicefunktioniert, ohne dass dazwischenliegende Elemente erstellt werden müssen.
Michael
3
@Michael: Guter Punkt - aber wenn Sie dies tun, this[new_index] = undefinedwird tatsächlich ein undefinedArray in den Array-Slot vor dem richtigen Index gesetzt. ( [1,2,3].move(0,10)Wird z. B. 1in Steckplatz 10 und undefinedin Steckplatz 9 haben.) Wenn die Spärlichkeit in Ordnung ist, könnten wir this[new_index] = this.splice(old_index, 1)[0]auf den anderen Spleißaufruf verzichten (machen Sie ihn stattdessen zu einem if / else).
Reid
268

Hier ist ein Einzeiler, den ich auf JSPerf gefunden habe ...

Array.prototype.move = function(from, to) {
    this.splice(to, 0, this.splice(from, 1)[0]);
};

Das ist großartig zu lesen, aber wenn Sie Leistung (in kleinen Datenmengen) wünschen, versuchen Sie ...

 Array.prototype.move2 = function(pos1, pos2) {
    // local variables
    var i, tmp;
    // cast input parameters to integers
    pos1 = parseInt(pos1, 10);
    pos2 = parseInt(pos2, 10);
    // if positions are different and inside array
    if (pos1 !== pos2 && 0 <= pos1 && pos1 <= this.length && 0 <= pos2 && pos2 <= this.length) {
      // save element from position 1
      tmp = this[pos1];
      // move element down and shift other elements up
      if (pos1 < pos2) {
        for (i = pos1; i < pos2; i++) {
          this[i] = this[i + 1];
        }
      }
      // move element up and shift other elements down
      else {
        for (i = pos1; i > pos2; i--) {
          this[i] = this[i - 1];
        }
      }
      // put element from position 1 to destination
      this[pos2] = tmp;
    }
  }

Ich kann keinen Kredit aufnehmen, alles sollte an Richard Scarrott gehen . In diesem Leistungstest übertrifft es die spleißbasierte Methode für kleinere Datensätze . Bei größeren Datenmengen ist es jedoch erheblich langsamer, wie Darwayne betont .

Digiguru
quelle
2
Ihre leistungsfähigere Lösung ist bei großen Datenmengen langsamer. jsperf.com/array-prototype-move/8
Darwayne
44
Dies scheint ein wirklich dummer Handel zu sein. Die Leistung bei kleinen Datenmengen ist ein vernachlässigbarer Gewinn, aber der Verlust bei großen Datenmengen ist ein erheblicher Verlust. Ihr Nettotausch ist negativ.
Kyeotic
3
@ Reid Das war keine Voraussetzung. IMO ist es in Ordnung anzunehmen, dass die Länge des Arrays nicht geändert wird.
Robsch
3
Eine Einzellösung muss zwei Situationen bewältigen:from >= to ? this.splice(to, 0, this.splice(from, 1)[0]) : this.splice(to - 1, 0, this.splice(from, 1)[0]);
Rob L
13
Bitte ändern Sie niemals eingebaute Prototypen. nczonline.net/blog/2010/03/02/…
LJHarb
230

Ich mag diesen Weg. Es ist prägnant und es funktioniert.

function arraymove(arr, fromIndex, toIndex) {
    var element = arr[fromIndex];
    arr.splice(fromIndex, 1);
    arr.splice(toIndex, 0, element);
}

Hinweis: Denken Sie immer daran, Ihre Array-Grenzen zu überprüfen.

Führen Sie Snippet auf jsFiddle aus

SteakOverflow
quelle
29
Da Array.splice die entfernten Werte in einem neuen Array zurückgibt, können Sie es als Einzeiler schreiben ... arr.splice (index + 1, 0, arr.splice (index, 1) [0]);
Eric
49
Persönlich bevorzuge ich den 3-Zeilen-Code. Es ist einfacher zu verstehen: Holen Sie sich eine Kopie des Elements; entferne es aus dem Array; Setzen Sie es an einer neuen Position ein. Der eine Liner ist kürzer, aber für andere nicht so klar zu verstehen ...
Philipp
2
Kurzer und einfacher Code. Aber es ist 2019 !!, Erstellen Sie einen Klon des Arrays und geben Sie ihn zurück, anstatt das Array zu mutieren. Dadurch wird Ihre Funktion "arraymove" den funktionalen Programmierstandards entsprechen
SamwellTarly
4
OK, aber nicht alles ist und muss funktional programmierfähig sein. Außerdem kann dies bei der funktionalen Programmierung innerhalb einer Prozedur zur Manipulation lokaler Arrays weiterhin nützlich sein.
SteakOverflow
36

Die splice () -Methode fügt / entfernt Elemente zu / von einem Array hinzu und gibt die entfernten Elemente zurück .

Hinweis: Diese Methode ändert das ursprüngliche Array. / w3schools /

Array.prototype.move = function(from,to){
  this.splice(to,0,this.splice(from,1)[0]);
  return this;
};

var arr = [ 'a', 'b', 'c', 'd', 'e'];
arr.move(3,1);//["a", "d", "b", "c", "e"]


var arr = [ 'a', 'b', 'c', 'd', 'e'];
arr.move(0,2);//["b", "c", "a", "d", "e"]

Da die Funktion verkettbar ist, funktioniert dies auch:

alert(arr.move(0,2).join(','));

Demo hier


quelle
Gibt es eine Bibliothek, die dies verwendet? Ziemlich ordentlich!
Uicoded
Weitere Kommentare dazu: Es ist eine schlechte Idee, integrierte Prototypen wie Array und Object zu ändern. Sie werden Dinge brechen.
Geoidesic
27

Mein 2c. Einfach zu lesen, es funktioniert, es ist schnell, es werden keine neuen Arrays erstellt.

function move(array, from, to) {
  if( to === from ) return array;

  var target = array[from];                         
  var increment = to < from ? -1 : 1;

  for(var k = from; k != to; k += increment){
    array[k] = array[k + increment];
  }
  array[to] = target;
  return array;
}
Merc
quelle
2
Bei der ersten Funktionszeichenfolge sollten Sie arraywie am Ende zurückkehren.
Sergey Voronezhskiy
3
Stimmt, wie habe ich das vermisst? Fest!
Merc
Ihre einfache und flexible Lösung gefällt mir am besten. Danke!
Roman M. Koss
18

Ich habe die Idee von @Reid, etwas an die Stelle des Elements zu schieben, das verschoben werden soll, um die Arraygröße konstant zu halten. Das vereinfacht die Berechnungen. Das Verschieben eines leeren Objekts hat außerdem den zusätzlichen Vorteil, dass es später eindeutig gesucht werden kann. Dies funktioniert, weil zwei Objekte nicht gleich sind, bis sie sich auf dasselbe Objekt beziehen.

({}) == ({}); // false

Hier ist also die Funktion, die das Quellarray und die Quell- und Zielindizes berücksichtigt. Sie können es bei Bedarf zum Array.prototype hinzufügen.

function moveObjectAtIndex(array, sourceIndex, destIndex) {
    var placeholder = {};
    // remove the object from its initial position and
    // plant the placeholder object in its place to
    // keep the array length constant
    var objectToMove = array.splice(sourceIndex, 1, placeholder)[0];
    // place the object in the desired position
    array.splice(destIndex, 0, objectToMove);
    // take out the temporary object
    array.splice(array.indexOf(placeholder), 1);
}
Anurag
quelle
1
Das sieht vielversprechend aus ... und das wusste ich nicht über Javascript js Vergleiche. Vielen Dank!
Mark Brown
Funktioniert nicht für den Fall sourceIndex = 0,destIndex = 1
Sergey Voronezhskiy
destIndexsoll der Index sein, bevor das Quellelement in das Array verschoben wird.
Anurag
Dies ist die bisher beste Antwort. Andere Antworten scheiterten ein paar Unit-Tests in meiner Suite (Objekt vorwärts bewegen)
Ilya Ivanov
16

Dies basiert auf der Lösung von @ Reid. Außer:

  • Ich ändere den ArrayPrototyp nicht.
  • Wenn Sie ein Objekt außerhalb der Grenzen nach rechts verschieben, werden keine undefinedElemente erstellt, sondern nur das Objekt an die Position ganz rechts verschoben.

Funktion:

function move(array, oldIndex, newIndex) {
    if (newIndex >= array.length) {
        newIndex = array.length - 1;
    }
    array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]);
    return array;
}

Unit Tests:

describe('ArrayHelper', function () {
    it('Move right', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 0, 1);
        assert.equal(array[0], 2);
        assert.equal(array[1], 1);
        assert.equal(array[2], 3);
    })
    it('Move left', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 1, 0);
        assert.equal(array[0], 2);
        assert.equal(array[1], 1);
        assert.equal(array[2], 3);
    });
    it('Move out of bounds to the left', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 1, -2);
        assert.equal(array[0], 2);
        assert.equal(array[1], 1);
        assert.equal(array[2], 3);
    });
    it('Move out of bounds to the right', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 1, 4);
        assert.equal(array[0], 1);
        assert.equal(array[1], 3);
        assert.equal(array[2], 2);
    });
});
André Pena
quelle
Dies ist falsch, wenn Sie eine Post-Position einfügen, ändert sich der Index, da Sie den Artikel entfernt haben
Yao Zhao
Vielen Dank. Ich wollte ein Element aus einem Array entfernen, ohne ein Null-Element zu hinterlassen (was bei der Verwendung von Splice (indexToRemove) auftrat. Ich habe Ihre Methode verwendet, um das Element, das ich entfernen wollte, an das Ende des Arrays zu verschieben, und dann pop () verwendet. Methode zu entfernen.
Luke Schoen
mochte die Funktion "Verschiebe den Gegenstand an die Position ganz rechts", die für meinen Fall nützlich ist. thx
bFunc
11

Hier ist meine Einzeiler-ES6-Lösung mit einem optionalen Parameter on.

if (typeof Array.prototype.move === "undefined") {
  Array.prototype.move = function(from, to, on = 1) {
    this.splice(to, 0, ...this.splice(from, on))
  }
}

Anpassung der ersten von vorgeschlagenen Lösung digiguru

Der Parameter onist die Anzahl der Elemente, ab denen fromSie sich bewegen möchten.

Elie Teyssedou
quelle
Die Lösung ist in Ordnung. Wenn Sie jedoch einen Prototyp erweitern, sollten Sie die Pfeilfunktion nicht verwenden, da in diesem Fall 'this' keine Array-Instanz, sondern beispielsweise ein Window-Objekt ist.
Wawka
7

Ein Ansatz wäre, mithilfe der Slice-Methode ein neues Array mit den Teilen in der gewünschten Reihenfolge zu erstellen.

Beispiel

var arr = [ 'a', 'b', 'c', 'd', 'e'];
var arr2 = arr.slice(0,1).concat( ['d'] ).concat( arr.slice(2,4) ).concat( arr.slice(4) );
  • arr.slice (0,1) gibt dir ['a']
  • arr.slice (2,4) gibt dir ['b', 'c']
  • arr.slice (4) gibt dir ['e']
Jared Updike
quelle
1
Sie erkennen, dass Sie arr2aufgrund der Verkettungsoperationen eine Zeichenfolge sind, oder? :) Es endet damit "adc,de".
Ken Franqueiro
6

Die spliceMethode von Arraykönnte helfen: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice

Denken Sie daran, dass dies relativ teuer sein kann, da das Array aktiv neu indiziert werden muss.

Ken Franqueiro
quelle
Ja, aber sobald ich den Spleiß durchführe, werden die Array-Indizes aktualisiert, was es für mich schwierig macht, herauszufinden, wo das gerade entfernte Element platziert werden soll. Zumal ich die Funktion brauche, um Bewegungen in beide Richtungen ausführen zu können.
Mark Brown
@Mark: Spleißen Sie die Zeichenfolge nicht und speichern Sie sie in derselben Variablen. Erstellen Sie eine neue Zeichenfolge und verbinden Sie diese. Siehe meine Antwort unten.
Jared Updike
6

Sie können einige grundlegende Berechnungen implementieren und eine universelle Funktion zum Verschieben von Array-Elementen von einer Position zur anderen erstellen.

Für JavaScript sieht es so aus:

function magicFunction (targetArray, indexFrom, indexTo) { 

    targetElement = targetArray[indexFrom]; 
    magicIncrement = (indexTo - indexFrom) / Math.abs (indexTo - indexFrom); 

    for (Element = indexFrom; Element != indexTo; Element += magicIncrement){ 
        targetArray[Element] = targetArray[Element + magicIncrement]; 
    } 

    targetArray[indexTo] = targetElement; 

}

Weitere Informationen finden Sie unter "Verschieben von Array-Elementen" unter "gloommatter".

http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-function.html

Andrea
quelle
1
Dies sollte die richtige Antwort sein, da keine neuen Arrays zugewiesen werden. Vielen Dank!
4.
Die Verbindung ist unterbrochen.
Rokit
6

Ich habe hier eine unveränderliche ECMAScript 6Lösung implementiert , die auf der @MercAntwort von basiert :

const moveItemInArrayFromIndexToIndex = (array, fromIndex, toIndex) => {
  if (fromIndex === toIndex) return array;

  const newArray = [...array];

  const target = newArray[fromIndex];
  const inc = toIndex < fromIndex ? -1 : 1;

  for (let i = fromIndex; i !== toIndex; i += inc) {
    newArray[i] = newArray[i + inc];
  }

  newArray[toIndex] = target;

  return newArray;
};

Die Variablennamen können gekürzt werden, nur lange, damit sich der Code selbst erklären kann.

Barry Michael Doyle
quelle
definitiv eine bessere Antwort, Mutationen verursachen Nebenwirkungen
Matt Lo
1
Warum nicht einfach aus Neugier arraysofort zurückkehren fromIndex === toIndexund nur dann erstellen, newArraywenn dies nicht der Fall ist? Unveränderlichkeit bedeutet nicht, dass pro Funktionsaufruf eine neue Kopie erstellt werden muss, auch wenn keine Änderung vorliegt. Nur b / c nach dem Motiv für die längere Länge dieser Funktion zu fragen (im Vergleich zu Einzeilern auf Spleißbasis), ist Leistung und fromIndexkann toIndexje nach Verwendung häufig gleich sein .
Robert Monfera
5

Ich brauchte eine unveränderliche Verschiebungsmethode (eine, die das ursprüngliche Array nicht geändert hat), also habe ich die akzeptierte Antwort von @ Reid angepasst, um einfach Object.assign zu verwenden, um eine Kopie des Arrays zu erstellen, bevor der Spleiß ausgeführt wird.

Array.prototype.immutableMove = function (old_index, new_index) {
  var copy = Object.assign([], this);
  if (new_index >= copy.length) {
      var k = new_index - copy.length;
      while ((k--) + 1) {
          copy.push(undefined);
      }
  }
  copy.splice(new_index, 0, copy.splice(old_index, 1)[0]);
  return copy;
};

Hier ist eine jsfiddle, die es in Aktion zeigt .

Javid Jamae
quelle
Es ist immer gut zu sehen, wie Menschen Mutationen berücksichtigen.
Hooman Askari
4
    Array.prototype.moveUp = function (value, by) {
        var index = this.indexOf(value),
            newPos = index - (by || 1);

        if (index === -1)
            throw new Error("Element not found in array");

        if (newPos < 0)
            newPos = 0;

        this.splice(index, 1);
        this.splice(newPos, 0, value);
    };

    Array.prototype.moveDown = function (value, by) {
        var index = this.indexOf(value),
            newPos = index + (by || 1);

        if (index === -1)
            throw new Error("Element not found in array");

        if (newPos >= this.length)
            newPos = this.length;

        this.splice(index, 1);
        this.splice(newPos, 0, value);
    };



    var arr = ['banana', 'curyWurst', 'pc', 'remembaHaruMembaru'];

    alert('withiout changes= '+arr[0]+' ||| '+arr[1]+' ||| '+arr[2]+' ||| '+arr[3]);
    arr.moveDown(arr[2]);


    alert('third word moved down= '+arr[0] + ' ||| ' + arr[1] + ' ||| ' + arr[2] + ' ||| ' + arr[3]);
    arr.moveUp(arr[2]);
    alert('third word moved up= '+arr[0] + ' ||| ' + arr[1] + ' ||| ' + arr[2] + ' ||| ' + arr[3]);

http://plnkr.co/edit/JaiAaO7FQcdPGPY6G337?p=preview

Arthur Tsidkilov
quelle
2

Am Ende habe ich zwei davon kombiniert, um beim Bewegen kleiner und großer Entfernungen etwas besser zu arbeiten. Ich erhalte ziemlich konsistente Ergebnisse, aber dies könnte wahrscheinlich von jemandem, der klüger als ich ist, ein wenig optimiert werden, um für verschiedene Größen usw. unterschiedlich zu arbeiten.

Die Verwendung einiger anderer Methoden beim Bewegen von Objekten über kleine Entfernungen war erheblich schneller (x10) als die Verwendung von Spleiß. Dies kann sich je nach Array-Länge ändern, gilt jedoch für große Arrays.

function ArrayMove(array, from, to) {
    if ( Math.abs(from - to) > 60) {
        array.splice(to, 0, array.splice(from, 1)[0]);
    } else {
        // works better when we are not moving things very far
        var target = array[from];
        var inc = (to - from) / Math.abs(to - from);
        var current = from;
        for (; current != to; current += inc) {
            array[current] = array[current + inc];
        }
        array[to] = target;    
    }
}

http://jsperf.com/arraymove-many-sizes

Andrew Backer
quelle
2

Es wird an vielen Stellen angegeben ( Hinzufügen von benutzerdefinierten Funktionen zu Array.prototype ), dass das Spielen mit dem Array-Prototyp eine schlechte Idee sein könnte. Trotzdem habe ich das Beste aus verschiedenen Posts kombiniert und dabei modernes Javascript verwendet:

    Object.defineProperty(Array.prototype, 'immutableMove', {
        enumerable: false,
        value: function (old_index, new_index) {
            var copy = Object.assign([], this)
            if (new_index >= copy.length) {
                var k = new_index - copy.length;
                while ((k--) + 1) { copy.push(undefined); }
            }
            copy.splice(new_index, 0, copy.splice(old_index, 1)[0]);
            return copy
        }
    });

    //how to use it
    myArray=[0, 1, 2, 3, 4];
    myArray=myArray.immutableMove(2, 4);
    console.log(myArray);
    //result: 0, 1, 3, 4, 2

Hoffnung kann für jeden nützlich sein

BernieSF
quelle
2

Diese Version ist nicht für alle Zwecke ideal, und nicht jeder mag Kommaausdrücke, aber hier ist ein Einzeiler, der ein reiner Ausdruck ist und eine neue Kopie erstellt:

const move = (from, to, ...a) => (a.splice(to, 0, ...a.splice(from, 1)), a)

Eine leicht leistungsverbesserte Version gibt das Eingabearray zurück, wenn keine Verschiebung erforderlich ist. Für die unveränderliche Verwendung ist es weiterhin in Ordnung, da sich das Array nicht ändert und es immer noch ein reiner Ausdruck ist:

const move = (from, to, ...a) => 
    from === to 
    ? a 
    : (a.splice(to, 0, ...a.splice(from, 1)), a)

Der Aufruf von beiden ist

const shuffled = move(fromIndex, toIndex, ...list)

Das heißt, es ist auf die Verbreitung angewiesen, um eine neue Kopie zu erstellen. Die Verwendung einer festen Arität 3 movewürde entweder die Eigenschaft eines einzelnen Ausdrucks oder die zerstörungsfreie Natur oder den Leistungsvorteil von gefährden splice. Auch hier handelt es sich eher um ein Beispiel, das einige Kriterien erfüllt, als um einen Vorschlag für die Verwendung in der Produktion.

Robert Monfera
quelle
1

Array.move.js

Zusammenfassung

Verschiebt Elemente innerhalb eines Arrays und gibt ein Array zurück, das die verschobenen Elemente enthält.

Syntax

array.move(index, howMany, toIndex);

Parameter

index : Index, um den Elemente verschoben werden sollen. Wenn negativ, beginnt der Index am Ende.

howMany : Anzahl der Elemente, die aus dem Index verschoben werden sollen .

toIndex : Index des Arrays, in dem die verschobenen Elemente platziert werden sollen. Wenn negativ, beginnt toIndex am Ende.

Verwendungszweck

array = ["a", "b", "c", "d", "e", "f", "g"];

array.move(3, 2, 1); // returns ["d","e"]

array; // returns ["a", "d", "e", "b", "c", "f", "g"]

Polyfill

Array.prototype.move || Object.defineProperty(Array.prototype, "move", {
    value: function (index, howMany, toIndex) {
        var
        array = this,
        index = parseInt(index) || 0,
        index = index < 0 ? array.length + index : index,
        toIndex = parseInt(toIndex) || 0,
        toIndex = toIndex < 0 ? array.length + toIndex : toIndex,
        toIndex = toIndex <= index ? toIndex : toIndex <= index + howMany ? index : toIndex - howMany,
        moved;

        array.splice.apply(array, [toIndex, 0].concat(moved = array.splice(index, howMany)));

        return moved;
    }
});
Jonathan Neal
quelle
2
Obwohl es so .moveaussieht, als ob es funktionieren sollte (ich habe es nicht getestet), sollten Sie beachten, dass es nicht Teil eines Standards ist. Es ist auch gut, die Leute zu warnen, dass Polyfill / Monkeypatched-Funktionen einen Code beschädigen können, der davon ausgeht, dass alles, was aufzählbar ist, ihnen gehört.
Jeremy J Starcher
1
a = ["a", "b", "c"]; a.move (0,1,1); // a = ["a", "b", "c"] sollte ["b", "a", "c"] sein
Leonard Pauli
2
Diese Funktion ist veraltet und wird möglicherweise nicht mehr unterstützt. Seien Sie vorsichtig Siehe: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Mostafa
1

Ich habe die nette Antwort von @Reid verwendet , aber Schwierigkeiten gehabt , ein Element vom Ende eines Arrays einen Schritt weiter zu verschieben - zum Anfang (wie in einer Schleife ). Zum Beispiel sollte ['a', 'b', 'c'] durch Aufrufen von .move (2,3) zu ['c', 'a', 'b'] werden.

Ich habe dies erreicht, indem ich den Fall für new_index> = this.length geändert habe.

Array.prototype.move = function (old_index, new_index) {
        console.log(old_index + " " + new_index);
        while (old_index < 0) {
            old_index += this.length;
        }
        while (new_index < 0) {
            new_index += this.length;
        }
        if (new_index >= this.length) {
            new_index = new_index % this.length;
        }
        this.splice(new_index, 0, this.splice(old_index, 1)[0]);
        return this; // for testing purposes
    };
Marcel Böttcher
quelle
1

Als Ergänzung zu Reids ausgezeichneter Antwort (und weil ich nichts kommentieren kann); Sie können Modulo verwenden, um sowohl negative als auch zu große Indizes "überrollen" zu lassen:

function array_move(arr, old_index, new_index) {
  new_index =((new_index % arr.length) + arr.length) % arr.length;
  arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
  return arr; // for testing
}

// returns [2, 1, 3]
console.log(array_move([1, 2, 3], 0, 1)); 

Habe ich
quelle
Ja, da negative Indizes unterstützt werden, erscheint es meiner Meinung nach sinnvoll, zu große Indizes zu umbrechen, anstatt undefinierte Werte einzufügen.
Python1981
1

const move = (from, to, ...a) =>from === to ? a : (a.splice(to, 0, ...a.splice(from, 1)), a);
const moved = move(0, 2, ...['a', 'b', 'c']);
console.log(moved)

Shijo Rs
quelle
1

Ich dachte, das wäre ein Tauschproblem, aber das ist es nicht. Hier ist meine Einzeiler-Lösung:

const move = (arr, from, to) => arr.map((item, i) => i === to ? arr[from] : (i >= Math.min(from, to) && i <= Math.max(from, to) ? arr[i + Math.sign(to - from)] : item));

Hier ist ein kleiner Test:

let test = ['a', 'b', 'c', 'd', 'e'];
console.log(move(test, 0, 2)); // [ 'b', 'c', 'a', 'd', 'e' ]
console.log(move(test, 1, 3)); // [ 'a', 'c', 'd', 'b', 'e' ]
console.log(move(test, 2, 4)); // [ 'a', 'b', 'd', 'e', 'c' ]
console.log(move(test, 2, 0)); // [ 'c', 'a', 'b', 'd', 'e' ]
console.log(move(test, 3, 1)); // [ 'a', 'd', 'b', 'c', 'e' ]
console.log(move(test, 4, 2)); // [ 'a', 'b', 'e', 'c', 'd' ]
console.log(move(test, 4, 0)); // [ 'e', 'a', 'b', 'c', 'd' ]
cagdas_ucar
quelle
Nun, die Frage war nicht über das Austauschen von Gegenständen. Der Autor bat um eine Lösung für eine Insert-Strategie.
Andreas Dolk
In Bezug auf die vorliegende Frage ist dies objektiv die falsche Antwort.
Ben Steward
0
let ar = ['a', 'b', 'c', 'd'];

function change( old_array, old_index , new_index ){

  return old_array.map(( item , index, array )=>{
    if( index === old_index ) return array[ new_index ];
    else if( index === new_index ) return array[ old_index ];
    else return item;
  });

}

let result = change( ar, 0, 1 );

console.log( result );

Ergebnis:

["b", "a", "c", "d"]
Naycho334
quelle
0

    let oldi, newi, arr;
    
    if(newi !== oldi) {
      let el = this.arr.splice(oldi, 1);
      if(newi > oldi && newi === (this.arr.length + 2)) {
        this.arr.push("");
      }
      this.arr.splice(newi, 0, el);
      if(newi > oldi && newi === (this.arr.length + 2)) {
        this.arr.pop();
      }
    }

Behnam
quelle
1
Willkommen bei SO! Es gibt 21 zusätzliche Antworten ... also bitte nicht nur Code eingeben. Erläutern Sie den Nutzen Ihrer Antwort.
David García Bodego
0

var ELEMS = ['a', 'b', 'c', 'd', 'e'];
/*
    Source item will remove and it will be placed just after destination
*/
function moveItemTo(sourceItem, destItem, elements) {
    var sourceIndex = elements.indexOf(sourceItem);
    var destIndex = elements.indexOf(destItem);
    if (sourceIndex >= -1 && destIndex > -1) {
        elements.splice(destIndex, 0, elements.splice(sourceIndex, 1)[0]);
    }
    return elements;
}
console.log('Init: ', ELEMS);
var result = moveItemTo('a', 'c', ELEMS);
console.log('BeforeAfter: ', result);

Mohd Abdul Baquee
quelle
0

Unveränderliche Version ohne Array-Kopie:

const moveInArray = (arr, fromIndex, toIndex) => {
  if (toIndex === fromIndex || toIndex >= arr.length) return arr;

  const toMove = arr[fromIndex];
  const movedForward = fromIndex < toIndex;

  return arr.reduce((res, next, index) => {
    if (index === fromIndex) return res;
    if (index === toIndex) return res.concat(
      movedForward ? [next, toMove] : [toMove, next]
    );

    return res.concat(next);
  }, []);
};
VoloshinS
quelle
0

Ich denke, der beste Weg ist, eine neue Eigenschaft für Arrays zu definieren

Object.defineProperty(Array.prototype, 'move', {
    value: function (old_index, new_index) {
        while (old_index < 0) {
            old_index += this.length;
        }
        while (new_index < 0) {
            new_index += this.length;
        }
        if (new_index >= this.length) {
            let k = new_index - this.length;
            while ((k--) + 1) {
                this.push(undefined);
            }
        }
        this.splice(new_index, 0, this.splice(old_index, 1)[0]);
        return this;
    }
});

console.log([10, 20, 30, 40, 50].move(0, 1));  // [20, 10, 30, 40, 50]
console.log([10, 20, 30, 40, 50].move(0, 2));  // [20, 30, 10, 40, 50]
iProDev
quelle
0

Eine weitere reine JS-Variante mit ES6-Array-Spread-Operator ohne Mutation

const reorder = (array, sourceIndex, destinationIndex) => {
	const smallerIndex = Math.min(sourceIndex, destinationIndex);
	const largerIndex = Math.max(sourceIndex, destinationIndex);

	return [
		...array.slice(0, smallerIndex),
		...(sourceIndex < destinationIndex
			? array.slice(smallerIndex + 1, largerIndex + 1)
			: []),
		array[sourceIndex],
		...(sourceIndex > destinationIndex
			? array.slice(smallerIndex, largerIndex)
			: []),
		...array.slice(largerIndex + 1),
	];
}

// returns ['a', 'c', 'd', 'e', 'b', 'f']
console.log(reorder(['a', 'b', 'c', 'd', 'e', 'f'], 1, 4))
      
 

abr
quelle
0

Diese Methode behält das ursprüngliche Array bei und prüft auf Begrenzungsfehler.

const move = (from, to, arr) => {
    to = Math.max(to,0)
    from > to 
        ? [].concat(
            arr.slice(0,to), 
            arr[from], 
            arr.filter((x,i) => i != from).slice(to)) 
        : to > from
            ? [].concat(
                arr.slice(0, from), 
                arr.slice(from + 1, to + 1), 
                arr[from], 
                arr.slice(to + 1))
            : arr}
Nikk Wong
quelle