将数组元素从一个数组位置移动到另一数组位置


521

我很难弄清楚如何移动数组元素。例如,给出以下内容:

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

我为什么能写入移动功能'd'之前,'b'

'a'之后'c'

移动之后,应更新其余元素的索引。这意味着在第一个示例中,移动后arr [0] ='a',arr [1] ='d'arr [2] ='b',arr [3] ='c',arr [4] = 'e'

这看起来应该很简单,但是我无法将其包裹住。


3
好这个问题古老但黄金
贾拉勒

使用ES6const changeValuePosition = (arr, init, target) => {[arr[init],arr[target]] = [arr[target],arr[init]]; return arr}
muhsalaa

只是交换了init和处的元素target
Matt F.

Answers:


671

如果您想在npm上使用某个版本,则array-move与该答案最接近,尽管它的实现方式不同。有关更多详细信息,请参见其用法部分。可以在npm的array.prototype.move上找到此答案的先前版本(修改后的Array.prototype.move)。


使用此功能,我取得了相当不错的成功:

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

请注意,最后一个return仅用于测试目的:splice就地对数组执行操作,因此不需要返回。通过扩展,这move是就地操作。如果要避免这种情况并返回副本,请使用slice

逐步执行代码:

  1. 如果 new_index大于数组的长度,我们(我想)用new undefineds 正确填充数组。这个小片段通过推动来处理undefined数组直到我们拥有适当的长度来。
  2. 然后,在中arr.splice(old_index, 1)[0],我们拼接出旧元素。splice返回被拼接的元素,但是它在数组中。在上面的示例中,这是[1]。因此,我们采用该数组的第一个索引来获取原始1
  3. 然后,我们使用splice此元素插入new_index的位置。由于我们在上面填充数组new_index > arr.length,除非它们做了一些奇怪的事情,例如传递负数,否则它可能会出现在正确的位置。

解释负指数的更高级的版本:

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

哪个应该占这样的事情 array_move([1, 2, 3], -1, -2)(将最后一个元素移到倒数第二个位置)。结果应该是[1, 3, 2]

无论哪种方式,在您最初的问题中,您都array_move(arr, 0, 2)将为aafter 做c。对于d以前b,你会做array_move(arr, 3, 1)


19
这样完美!您的解释很清楚。感谢您抽出宝贵的时间来编写此内容。
马克·布朗

16
您不应该操作对象和数组原型,它会在迭代元素时引起问题。
burak emre

9
@burakemre:我认为结论还不太清楚。大多数优秀的JS程序员(和最受欢迎的库).hasOwnProperty在对诸如..in之类的东西进行迭代时都会使用检查,尤其是对于像Prototype和MooTools这样的库,它们会修改原型。无论如何,在这样的相对有限的示例中,我并不认为这是一个特别重要的问题,并且在原型修改是否是一个好主意方面,社区之间存在很大分歧。通常,迭代问题是最不用担心的。
2013年

3
在步骤1中不需要循环,您只需this[new_index] = undefined;在该if块内使用即可。由于Javascript数组稀疏,这将扩展数组的大小,使其包含new_index以.splice使其起作用,而无需创建任何中间元素。
迈克尔

3
@Michael:好点-但是这样做this[new_index] = undefined实际上会在正确的索引之前undefined在数组插槽中放置一个。(例如,将在插槽10和插槽9中。)相反,如果稀疏性还可以,我们可以不用其他的拼接调用(而是将其设为if / else)。[1,2,3].move(0,10)1undefinedthis[new_index] = this.splice(old_index, 1)[0]
Reid

268

这是我在JSPerf上找到的一个衬板。

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

很棒,但是如果您想要性能(在小型数据集中),请尝试...

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

我不能相信,应该全部归理查德·斯卡罗特所有。在此性能测试中,它击败了基于拼接的较小数据集方法。但是,正如Darwayne指出的那样,在较大的数据集上它要慢得多。


2
在大型数据集上,性能更高的解决方案速度较慢。jsperf.com/array-prototype-move/8
达尔文,

44
这似乎是一个非常愚蠢的权衡。小数据集的性能可以忽略不计,但是大数据集的性能损失是很大的损失。您的净交换是负数。
Kyeotic

3
@Reid这不是必须的。IMO可以假设数组的长度没有被修改。
罗布施

3
一种解决方案需要处理两种情况:from >= to ? this.splice(to, 0, this.splice(from, 1)[0]) : this.splice(to - 1, 0, this.splice(from, 1)[0]);
Rob L

13
请永远不要修改内置的原型。nczonline.net/blog/2010/03/02/...
LJHarb

229

我喜欢这样 简洁明了且有效。

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

注意:请务必记住检查数组边界。

在jsFiddle上运行代码段


29
由于Array.splice在新的Array中返回删除的值,因此您可以将其写为一个衬里。
埃里克

49
我个人更喜欢3行代码。更容易理解:获取元素的副本;从数组中删除它;将其插入新位置。一个衬套较短,但对其他人却不太清楚...
Philipp

2
简短的代码。但是现在是2019年!!,创建数组的副本并返回它而不是使数组变异。这将使您的函数“ arraymove”符合函数编程标准
SamwellTarly,

3
OK,但不是一切都不也不是必须是函数式编程兼容; 另外,这在处理本地数组的过程中的函数式编程中仍然有用。
SteakOverflow

36

splice()方法在数组中添加/删除项目,并返回删除的项目。

注意:此方法更改原始数组。/ 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"]

由于该函数是可链接的,因此也可以工作:

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

在这里演示


有没有使用此库的库?挺整洁的!
2016年

请参阅有关此内容的其他评论:修改诸如Array和Object之类的内置原型是一个坏主意。你会破坏事情。
geoidesic '18

27

我的2c。易于阅读,有效,快速,不会创建新数组。

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

2
在函数的第一个字符串中,您应该返回array,就像最后一样。
谢尔盖·沃罗涅

3
真的,我怎么想念它?固定!
Merc

我最喜欢您简单灵活的解决方案。谢谢!
罗曼·科斯

18

从@Reid那里得到了这个想法,即在应该移动的位置上推一些东西以保持数组大小不变。这确实简化了计算。同样,推入一个空对象还有一个额外的好处,就是以后可以唯一地搜索它。之所以可行,是因为两个对象在引用同一对象之前是不相等的。

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

因此,这里是接收源数组以及源索引和目标索引的函数。您可以根据需要将其添加到Array.prototype中。

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

1
这看起来很有希望...而且我不了解javascript js比较。谢谢!
马克·布朗

不适用于案件sourceIndex = 0destIndex = 1
Sergey Voronezhskiy

destIndex是要作为源元素在数组中移动之前的索引。
阿努拉格(Anurag)

到目前为止,这是最好的答案。其他答案在我的套件中两次单元测试都失败了(向前移动对象)
Ilya Ivanov

16

这基于@Reid的解决方案。除了:

  • 我没有改变Array原型。
  • 将项目移出右边到边界不会创建undefined项目,而只是将项目移到最右边的位置。

功能:

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

单元测试:

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

这是错误的,如果您插入职位,则索引将发生变化,因为您已经删除了该项目
姚钊

谢谢。我想从数组中删除一个项目而不留下一个null元素(使用splice(indexToRemove)时会发生这种情况。我使用了您的方法将要删除的项目移动到数组的末尾,然后使用了pop()方法去除。
卢克舒恩

喜欢“将项目移动到最右边的位置”功能,这对我的情况很有用。thx
bFunc

11

这是我的带有可选参数的线性ES6解决方案on

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

适应第一个提出的解决方案 digiguru

参数onfrom您要移动的元素的数量。


解决方案很好。但是,在扩展原型时,不应使用箭头功能,因为在这种情况下,“ this”不是数组实例,而是Window对象。
wawka

7

一种方法是使用slice方法按所需顺序创建一个新数组。

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)给您['a']
  • arr.slice(2,4)给您['b','c']
  • arr.slice(4)给您['e']

1
您确实意识到arr2由于连接操作,最终以字符串结尾,对吗?:)最终成为"adc,de"
肯·弗兰克罗

6

splice方法Array可能会有所帮助: https //developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice

请记住,由于它必须主动重新索引阵列,因此它可能相对昂贵。


是的,但是一旦执行拼接,数组索引就会更新,这使我很难弄清楚将刚刚删除的元素放置在哪里。特别是因为我需要该功能能够处理两个方向的移动。
马克·布朗

@Mark:不要拼接字符串并将其保存到相同的变量中,创建一个新的字符串并将其拼接起来。请参阅下面的答案。
Jared Updike

6

您可以实现一些基本的微积分,并创建通用函数以将数组元素从一个位置移动到另一位置。

对于JavaScript,它看起来像这样:

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; 

}

请查看“积木”中的“移动数组元素”以获取详细说明。

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


1
这应该是正确的答案,因为它不会分配任何新的数组。谢谢!
2013年

链接断开。
Rokit

6

我在这里ECMAScript 6基于@Merc的答案实现了一个不变的解决方案:

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

变量名可以缩短,只需使用较长的变量名即可,以便代码可以自我解释。


绝对是一个更好的答案,突变会产生副作用
马特·罗

1
出于好奇,为什么不array立即返回if fromIndex === toIndex,而仅newArray在情况并非如此时创建?不变性并不意味着即使没有更改,也必须为每个函数调用创建一个新副本。仅向b / c询问此功能的增加长度(相对于基于接头的单线)的动机就是性能,并且fromIndex可能经常相等toIndex,这取决于用法。
罗伯特·蒙菲拉

5

我需要一个不变的move方法(一个不会更改原始数组的方法),因此我修改了@Reid的可接受答案,以简单地使用Object.assign在进行拼接之前创建数组的副本。

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

这是一个jsfiddle,显示了它的作用


最好看到ppl将突变考虑在内。
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


2

最后,我将这两种方法结合起来,无论在长距离还是短距离移动时,效果都更好。我得到了相当一致的结果,但是这可能会被比我聪明的人进行一些调整,以针对不同的尺寸进行不同的工作,等等。

当移动物体较小距离时,使用其他一些方法比使用拼接要快得多(x10)。但是,这可能会根据数组的长度而变化,但是对于大型数组而言确实如此。

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


2

据说在很多地方(将自定义函数添加到Array.prototype中)与Array原型一起玩可能是一个坏主意,无论如何,我使用现代Javascript结合了各种文章中的最佳技巧:

    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

希望对任何人都有用


2

这个版本并不是在所有情况下都是理想的,并不是每个人都喜欢逗号表达式,但这是一个纯粹的表达式的单线创建新的副本:

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

如果不需要任何移动,经过稍微提高性能的版本将返回输入数组,它仍然可以用于不可变的用途,因为该数组不会更改,并且仍然是纯表达式:

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

两者之一的调用是

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

也就是说,它依靠传播来生成新副本。使用固定的arity 3 move会危害单一的表达属性或非破坏性的性质,或的性能优势splice。同样,它更像是满足某些标准的示例,而不是针对生产用途的建议。


1

Array.move.js

摘要

在数组中移动元素,返回包含已移动元素的数组。

句法

array.move(index, howMany, toIndex);

参量

index:元素移动的索引。如果为负,索引将从末尾开始。

howMany:要从索引移动的元素数。

toIndex:放置移动元素的数组的索引。如果为负,则toIndex将从结尾开始。

用法

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

2
尽管.move看起来它应该可以工作(我还没有测试过),但是您应该注意它不是任何标准的一部分。警告人们,polyfill / monkeypatched函数可能会破坏一些假设所有可枚举内容的代码,这也很好。
杰里米·J·斯塔彻

1
a = [“ a”,“ b”,“ c”]; a.move(0,1,1); // a = [“ a”,“ b”,“ c”],应为[“ b”,“ a”,“ c”]
Leonard Pauli

2
该功能已过时,可能不再受支持。请注意:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…–
Mostafa

1

我使用了@Reid的好答案,但是在将元素从数组的末尾进一步移动到开始的过程中很费劲(就像在循环中一样))。例如,应通过调用.move(2,3)将['a','b','c']变为['c','a','b']

我通过更改new_index> = this.length的大小写实现了这一点。

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

1

作为Reid出色回答的补充(并且因为我无法发表评论);您可以使用模数使负索引和太大的索引“翻转”:

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


是的-因为支持负索引,所以我认为包装太大的索引而不是插入未定义的值似乎是明智的。
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)


1

我以为这是交换问题,但不是。这是我的一线解决方案:

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

这是一个小测试:

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' ]

好吧,问题不在于交换项目。作者要求一种插入策略的解决方案。
Andreas Dolk

关于眼前的问题,这在客观上是错误的答案。
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 );

结果:

["b", "a", "c", "d"]

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


1
欢迎来到SO!还有21个其他答案...所以,请不要只是放置代码。解释您回答的好处。
DavidGarcíaBodego,

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


0

不带数组副本的不可变版本:

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);
  }, []);
};

0

我认为最好的方法是为数组定义一个新属性

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]

0

使用ES6数组扩展算子且无突变的另一个纯JS变体

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


0

此方法将保留原始数组,并检查边界错误。

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}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.