Website-Suche

javascript - Ein Array-Element von einer Array-Position zu einer anderen verschieben


Ich habe Schwierigkeiten herauszufinden, wie man ein Element eines Arrays verschiebt. Zum Beispiel, gegeben das Folgende:

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

Wie kann ich eine Funktion schreiben, um das Element 'd' nach links von 'b' zu verschieben?

Oder 'a' rechts von 'c'?

Nach dem Verschieben der Elemente sollten die Indizes der restlichen Elemente aktualisiert werden. Das resultierende Array wäre:

array = ['a', 'd', 'b', 'c', 'e']

Das scheint ziemlich einfach zu sein, aber ich kann es nicht begreifen.

Antwort #1

Wenn Sie eine Version auf npm möchten, ist array-move der dieser Antwort am nächsten kommende, obwohl es nicht die gleiche Implementierung ist. Siehe den Abschnitt zur Verwendung für weitere Details. Die vorherige Version dieser Antwort (die Array.prototype.move geändert hat) kann auf npm unter array.prototype.move gefunden werden.

Ich hatte ziemlich guten Erfolg 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 das letzte return nur zu Testzwecken dient: splice führt Operationen direkt am Array durch, daher ist ein Rückgabewert nicht erforderlich. Folglich ist auch dieses move eine In-Place-Operation. Wenn Sie das vermeiden und eine Kopie zurückgeben möchten, verwenden Sie slice.

Schrittweise durch den Code gehen:

  1. Wenn new_index größer als die Länge des Array ist, wollen wir (vermute ich) das Array richtig mit neuen undefined-Werten auffüllen. Dieses kleine Snippet erledigt dies, indem es undefined in das Array einfügt, bis wir die richtige Länge haben.
  2. Dann spalten wir in arr.splice(old_index, 1)[0] das alte Element aus. splice gibt das ausgespaltete Element zurück, aber es ist in einem Array. In unserem obigen Beispiel war dies [1]. Also nehmen wir den ersten Index dieses Arrays, um das rohe 1 dort zu erhalten.
  3. Dann verwenden wir splice, um dieses Element an der Stelle von new_index einzufügen. Da wir das Array oben aufgefüllt haben, falls new_index > arr.length, wird es wahrscheinlich an der richtigen Stelle erscheinen, es sei denn, sie haben etwas Seltsames getan, wie zum Beispiel eine negative Zahl übergeben.

Eine ausgefallenere 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 (das letzte Element an die vorletzte Stelle verschieben). Das Ergebnis dafür sollte [1, 3, 2] sein.

So oder so, in Ihrer ursprünglichen Frage würden Sie array_move(arr, 0, 2) für a nach c verwenden. Für d vor b würden Sie array_move(arr, 3, 1) verwenden.

Antwort #2

Ich mag diese Methode, da sie prägnant ist und einfach funktioniert.

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

Hinweis: Denken Sie immer daran, die Grenzen Ihres Arrays zu überprüfen.

Der folgende Ausschnitt druckt einige Tests in der Konsole, um zu zeigen, dass alle Kombinationen von fromIndex und toIndex (0..n, 0..n) funktionieren.

Snippet in jsFiddle ausführen

Antwort #3

Hier ist eine Einzeilige, die ich auf JSPerf gefunden habe....

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

was großartig zu lesen ist, aber wenn du Leistung (bei kleinen Datensätzen) willst, versuche...

 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 Verdienst dafür beanspruchen, er sollte ganz Richard Scarrott zugeschrieben werden. In diesem Leistungstest schlägt es die splicing-basierte Methode für kleinere Datensätze. Wie Darwayne jedoch hervorhebt, ist es bei größeren Datensätzen deutlich langsamer.

Antwort #4

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

Hinweis: Diese Methode verä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 verketten kann, funktioniert dies auch:

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

Demo hier

Antwort #5

Meine 2 Cent. Leicht zu lesen, es funktioniert, es ist schnell, es erzeugt keine neuen Arrays.

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

Antwort #6

Hier ist meine einzeilige 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 digiguru vorgeschlagenen Lösung

Der Parameter on ist die Anzahl der Elemente, beginnend bei from, die Sie verschieben möchten.

Hier ist eine verkettbare Variante davon:

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

[3, 4, 5, 1, 2].move(3, 0, 2) // => [1, 2, 3, 4, 5]

Wenn Sie Prototype Pollution vermeiden möchten, hier ist eine eigenständige Funktion:

function move(array, from, to, on = 1) {
  return array.splice(to, 0, ...array.splice(from, on)), array
}

move([3, 4, 5, 1, 2], 3, 0, 2) // => [1, 2, 3, 4, 5]

Und schließlich hier eine reine Funktion, die das ursprüngliche Array nicht verändert:

function moved(array, from, to, on = 1) {
  return array = array.slice(), array.splice(to, 0, ...array.splice(from, on)), array
}

Das sollte im Grunde jede in jeder anderen Antwort gesehene Variation abdecken.

Antwort #7

Ich habe diese Idee von @Reid übernommen, etwas anstelle des Elements einzufügen, das verschoben werden soll, um die Größe des Arrays konstant zu halten. Das vereinfacht die Berechnungen tatsächlich. Außerdem hat das Einfügen eines leeren Objekts den zusätzlichen Vorteil, dass man es später eindeutig suchen kann. Das funktioniert, weil zwei Objekte nur dann gleich sind, wenn sie auf dasselbe Objekt verweisen.

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

Also, hier ist die Funktion, die das Quellarray sowie die Quell- und Zielindizes übernimmt. Sie könnten sie bei Bedarf dem 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);
}

Antwort #8

Dies basiert auf @Reids Lösung. Außer:

  • Ich werde das Array-Prototyp nicht ändern.
  • Das Verschieben eines Elements außerhalb der Grenzen nach rechts erzeugt keine undefinierten Elemente, es verschiebt das Element nur an die äußerste rechte Position.

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

Modultests:

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

Antwort #9

Sie können einige grundlegende Kalküle implementieren und eine universelle Funktion erstellen, um Array-Elemente von einer Position zur anderen zu verschieben.

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; 

}

Schau dir 'moving array elements' bei 'Gloommatter' für eine detaillierte Erklärung an.

https://web.archive.org/web/20121105042534/http://www.gloommatter.com:80/DDesign/programming/moving-any-array-elements-universal-function.html

Verwandte Artikel