Move an array element from one array position to another

后端 未结 30 2475
渐次进展
渐次进展 2020-11-22 08:36

I\'m having a hard time figuring out how to move an array element. For example, given the following:

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


        
相关标签:
30条回答
  • 2020-11-22 08:58

    Here's a one liner I found on JSPerf....

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

    which is awesome to read, but if you want performance (in small data sets) try...

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

    I can't take any credit, it should all go to Richard Scarrott. It beats the splice based method for smaller data sets in this performance test. It is however significantly slower on larger data sets as Darwayne points out.

    0 讨论(0)
  • 2020-11-22 08:58

    My 2c. Easy to read, it works, it's fast, it doesn't create new 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;
    }
    
    0 讨论(0)
  • 2020-11-22 08:58

    This is based on @Reid's solution. Except:

    • I'm not changing the Array prototype.
    • Moving an item out of bounds to the right does not create undefined items, it just moves the item to the right-most position.

    Function:

    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);
        });
    });
    
    0 讨论(0)
  • 2020-11-22 08:58

    Array.move.js

    Summary

    Moves elements within an array, returning an array containing the moved elements.

    Syntax

    array.move(index, howMany, toIndex);
    

    Parameters

    index: Index at which to move elements. If negative, index will start from the end.

    howMany: Number of elements to move from index.

    toIndex: Index of the array at which to place the moved elements. If negative, toIndex will start from the end.

    Usage

    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;
        }
    });
    
    0 讨论(0)
  • 2020-11-22 08:58

    As an addition to Reid's excellent answer (and because I cannot comment); You can use modulo to make both negative indices and too large indices "roll over":

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

    0 讨论(0)
  • 2020-11-22 08:59

    I needed an immutable move method (one that didn't change the original array), so I adapted @Reid's accepted answer to simply use Object.assign to create a copy of the array before doing the splice.

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

    Here is a jsfiddle showing it in action.

    0 讨论(0)
提交回复
热议问题