ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

如何编写函数将元素 'd' 移动到 'b' 的左侧?

还是 'c' 右侧的 'a'

移动元素后,应更新其余元素的索引。结果数组将是:

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

这似乎应该很简单,但我无法理解它。

使用 ES6 const changeValuePosition = (arr, init, target) => {[arr[init],arr[target]] = [arr[target],arr[init]]; return arr}
这只是交换 inittarget 处的元素。
@user4945014 这不仅仅是交换。如果发生交换,OP 会得到 array = ['a', 'd', 'c', 'b', 'e'],这意味着 'c' 和 'b' 的顺序是错误的。他正在寻找的插入和移位将使“b”和“c”保持相同的顺序。

R
Reid

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

我在这个功能上取得了相当大的成功:

函数 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]);返回 arr; // 用于检测 }; // 返回 [2, 1, 3] console.log(array_move([1, 2, 3], 0, 1));

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

单步执行代码:

如果 new_index 大于数组的长度,我们希望(我假设)用新的未定义正确地填充数组。这个小片段通过在数组上推送 undefined 来处理这个问题,直到我们有适当的长度。然后,在 arr.splice(old_index, 1)[0] 中,我们拼接出旧元素。 splice 返回被拼接出来的元素,但它在一个数组中。在我们上面的例子中,这是 [1]。因此,我们采用该数组的第一个索引来获取原始 1。然后我们使用 splice 将这个元素插入到 new_index 的位置。因为如果 new_index > arr.length 我们填充了上面的数组,它可能会出现在正确的位置,除非他们做了一些奇怪的事情,比如传入一个负数。

一个更好的版本来解释负指数:

函数 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]);返回 arr; // 用于测试目的 }; // 返回 [1, 3, 2] console.log(array_move([1, 2, 3], -1, -2));

这应该正确考虑 array_move([1, 2, 3], -1, -2) 之类的事情(将最后一个元素移到倒数第二个位置)。结果应该是 [1, 3, 2]

无论哪种方式,在您最初的问题中,您都会在 c 之后为 a 执行 array_move(arr, 0, 2)。对于 b 之前的 d,您将执行 array_move(arr, 3, 1)


这完美!而且你的解释很清楚。感谢您花时间写这篇文章。
您不应该操纵 Object 和 Array 原型,它会在迭代元素时导致问题。
@burakemre:我认为这个结论并没有那么清楚。大多数优秀的 JS 程序员(和最流行的库)在使用诸如 for..in 之类的东西进行迭代时会使用 .hasOwnProperty 检查,尤其是使用诸如 Prototype 和 MooTools 等修改原型的库时。无论如何,在这样一个相对有限的示例中,我并不觉得这是一个特别重要的问题,并且社区中对于原型修改是否是一个好主意存在很好的分歧。不过,通常情况下,迭代问题是最不值得关注的。
步骤 1 中不需要循环,您只需在 if 块中使用 this[new_index] = undefined;。由于 Javascript 数组是稀疏的,这将扩展数组大小以包括 new_index 以使 .splice 工作,但无需创建任何中间元素。
请不要将此添加到原型中。当 TC39 想要将其本地添加到 JavaScript 时,他们将不得不使用一个不同的、尴尬的名称,因为人们这样做。
S
SteakOverflow

我喜欢这种方式。它简洁而且有效。

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

注意:永远记得检查你的数组边界。

Run Snippet in jsFiddle


由于 Array.splice 在新数组中返回已删除的值,因此您可以将其写为一个衬里... arr.splice(index + 1, 0, arr.splice(index, 1)[0]);
我个人更喜欢 3 行代码。更容易理解:获取元素的副本;从数组中删除它;将其插入新位置。一个班轮较短,但对其他人来说不太清楚......
简短而简单的代码。但现在是 2019 年!!,创建数组的克隆并返回它,而不是改变数组。这将使您的函数“arraymove”符合函数式编程标准
我永远不会想到,对于某些人来说,在 2019 年之后,原地变异数组会变得过时。完全合法的答案,+1。
现在是 2021 年。出于内存/性能原因,仍然存在复制完全不合适的情况。纯函数应该是默认的,但它不应该是教条。
t
tagurit

这是我在 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;
    }
  }

我不能把功劳归于Richard Scarrott。在此 performance test 中,它击败了基于拼接的较小数据集的方法。然而,在较大的数据集 as Darwayne points out 上,它的速度要慢得多。


您的性能更高的解决方案在大型数据集上速度较慢。 jsperf.com/array-prototype-move/8
这似乎是一个非常愚蠢的权衡。在小数据集上的性能可以忽略不计,但在大数据集上的损失是一个重大损失。你的净交换是负数。
@Reid这不是要求。 IMO 可以假设数组的长度没有被修改。
一条线解决方案需要处理两种情况:from >= to ? this.splice(to, 0, this.splice(from, 1)[0]) : this.splice(to - 1, 0, this.splice(from, 1)[0]);
请永远不要修改内置原型。 nczonline.net/blog/2010/03/02/…
C
Community

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

因为函数是 chainable 这也有效:

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

demo here


请参阅其他评论:修改内置原型(如 Array 和 Object)是个坏主意。你会弄坏东西。
M
Merc

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

在函数的第一个字符串中,您应该返回 array,就像它在结尾处所做的那样。
真的,我怎么会错过呢?固定的!
我最喜欢您的简单灵活的解决方案。谢谢!
A
Anurag

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

这看起来很有希望......而且我不知道关于 javascript js 比较。谢谢!
不适用于案例 sourceIndex = 0destIndex = 1
destIndex 是源元素在数组中移动之前的索引。
这是迄今为止最好的答案。其他答案在我的套件中未能通过几个单元测试(向前移动对象)
m
mindplay.dk

这是我的一个线性 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提出的第一个解决方案

参数 on 是要移动的从 from 开始的元素数。

这是一个可链接的变体:

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]

如果你想避免原型污染,这里有一个独立的函数:

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]

最后,这是一个不会改变原始数组的纯函数:

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

这应该基本上涵盖所有其他答案中看到的所有变化。


解决方案很好。但是,当您展开原型时,您不应该使用箭头函数,因为在这种情况下,“this”不是数组实例,而是例如 Window 对象。
这是我最喜欢的答案——现代、简洁和简单。我添加了一个可链接的变体,以与标准 Array 方法更加一致。有些人会对原型污染提出质疑,所以我也添加了一个独立的功能。最后,一些用例需要一个纯函数,而不是就地操作,所以我也添加了它。
我无法理解最后一个纯函数。该语句是否用逗号分隔?它是如何工作的?
@batbrain9392 - 检查这个问题:stackoverflow.com/q/10284536/1914985
A
Andre Pena

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

我没有更改 Array 原型。

将项目向右移出边界不会创建未定义的项目,它只是将项目移动到最右边的位置。

功能:

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

这是错误的,如果您插入帖子位置,则索引将更改,因为您已删除该项目
谢谢你。我想从数组中删除一个项目而不留下空元素(使用 splice(indexToRemove) 时发生这种情况。我使用您的方法将要删除的项目移动到数组的末尾,然后使用 pop()方法去除。
喜欢“将项目移动到最右边的位置”功能,对我的情况很有用。谢谢
t
tagurit

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

对于 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; 

}

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

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


这应该是正确的答案,因为它没有分配任何新数组。谢谢!
链接已损坏。
解决方案很棒!我喜欢这个解决方案,因为它不使用拼接功能,但不适用于负索引,也不检查数组出站。
B
Barry Michael Doyle

我已经根据 @Merc 在此处的回答实施了一个不可变的 ECMAScript 6 解决方案:

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

变量名可以缩短,只使用长的,这样代码就可以解释自己了。


绝对是一个更好的答案,突变会产生副作用
出于好奇,如果是 fromIndex === toIndex,为什么不立即返回 array,如果不是这样,只创建 newArray?不变性并不意味着每次函数调用都必须创建一个新副本,即使没有更改也是如此。只是询问 b/c 增加此函数长度(相对于基于拼接的单行)的动机是性能,并且 fromIndex 很可能经常等于 toIndex,具体取决于使用情况。
J
Jared Updike

一种方法是使用 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']


您确实意识到由于连接操作,您的 arr2 最终成为一个字符串,对吧? :) 它最终是 "adc,de"
K
Ken Franqueiro

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

请记住,它可能相对昂贵,因为它必须主动重新索引数组。


是的,但是一旦我执行拼接,数组索引就会更新,这让我很难弄清楚将刚刚删除的元素放在哪里。特别是因为我需要该功能能够处理两个方向的移动。
@Mark:不要拼接字符串并将其保存到同一个变量中,创建一个新字符串并拼接它。请看下面我的回答。
a
abr

另一个使用 ES6 数组扩展运算符的纯 JS 变体,没有突变

const reorder = (array, sourceIndex, destinationIndex) => { const smallIndex = Math.min(sourceIndex, destinationIndex); const largeIndex = Math.max(sourceIndex,destinationIndex); return [ ...array.slice(0, smallIndex), ...(sourceIndex destinationIndex ? array.slice(smallerIndex, largeIndex) : []), ...array.slice(largerIndex + 1), ]; } // 返回 ['a', 'c', 'd', 'e', 'b', 'f'] console.log(reorder(['a', 'b', 'c', 'd ', 'e', 'f'], 1, 4))


我个人很喜欢这个,下次搜索会再次遇到这个......所以添加我自己的个性化实现...... const swapIndex = (array, from, to) => (from < to ? [...array.slice (0, from), ...array.slice(from + 1, to + 1), array[from], ...array.slice(to + 1)] : [...array.slice(0, to), array[from], ...array.slice(to, from), ...array.slice(from + 1)]);
J
Javid Jamae

我需要一个不可变的移动方法(一个不改变原始数组的方法),所以我调整了@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 showing it in action


看到 ppl 考虑突变总是很好的。
C
Caveman

这是以不可变的方式执行此操作的一种方法。它处理负数以及额外的奖励。与编辑原始数组相比,这以性能为代价减少了可能的错误数量。

const numbers = [1, 2, 3];
const moveElement = (array, from, to) => {
  const copy = [...array];
  const valueToMove = copy.splice(from, 1)[0];
  copy.splice(to, 0, valueToMove);
  return copy;
};

console.log(moveElement(numbers, 0, 2))
// > [2, 3, 1]
console.log(moveElement(numbers, -1, -3))
// > [3, 1, 2] 

A
Arthur Tsidkilov
    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


D
Dudley Craig

我喜欢不可变的、功能性的单衬:) ...

const swapIndex = (array, from, to) => (
  from < to 
    ? [...array.slice(0, from), ...array.slice(from + 1, to + 1), array[from], ...array.slice(to + 1)] 
    : [...array.slice(0, to), array[from], ...array.slice(to, from), ...array.slice(from + 1)]
);

太棒了。谢谢!
B
BernieSF

在很多地方(adding custom functions into 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

希望对任何人都有用


R
Robert Monfera

这个版本并不适合所有目的,也不是每个人都喜欢逗号表达式,但这里有一个纯表达式的单行,创建一个新鲜的副本:

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 的性能优势。同样,它更像是一个满足某些标准的示例,而不是生产使用的建议。


S
Shijo Rs

const move = (from, to, ...a) =>from === to ? a : (a.splice(to, 0, ...a.splice(from, 1)), a);常量移动 = move(0, 2, ...['a', 'b', 'c']);控制台日志(移动)


c
cagdas_ucar

我认为这是一个交换问题,但事实并非如此。这是我的单线解决方案:

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

好吧,问题不在于交换物品。作者要求一种插入策略的解决方案。
关于手头的问题,这在客观上是错误的答案。
N
Nour Adel

这是一个使用拼接的非常简单的方法

Array.prototype.moveToStart = function(index) {
    this.splice(0, 0, this.splice(index, 1)[0]);
    return this;
  };

t
tagurit

我最终将其中两个结合起来,以便在移动小距离和大距离时更好地工作。我得到了相当一致的结果,但这可能会被比我聪明的人稍微调整一下,以针对不同的尺寸等进行不同的工作。

在小距离移动物体时使用其他一些方法比使用拼接要快得多(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;    
    }
}

https://web.archive.org/web/20181026015711/https://jsperf.com/arraymove-many-sizes


G
Gass

一种方法是使用 splice() 从数组中移除项目,然后再次使用 splice() 方法,将移除的项目插入到目标索引

const array = ['a', 'b', 'c', 'd', 'e'] const newArray = moveItem(array, 3, 1) // 将元素从索引 3 移动到索引 1 function moveItem(arr, fromIndex, toIndex){ let itemRemoved = arr.splice(fromIndex, 1) // 将移除的项目分配为数组 arr.splice(toIndex, 0, itemRemoved[0]) // 将 itemRemoved 插入目标索引 return arr } console .log(新数组)


J
Jonathan Neal

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

填充物

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

虽然 .move 看起来应该可以工作(我没有测试过),但您应该注意它不是任何标准的一部分。警告人们 polyfill/monkeypatched 函数可能会破坏一些假定所有可枚举都是他们的代码的人也很好。
a=["a", "b", "c"];a.move(0,1,1); // a = ["a", "b", "c"], 应该是 ["b", "a", "c"]
此功能已过时,可能不再受支持。小心请参阅:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
C
Community

我使用了不错的 answer of @Reid,但是在将一个元素从数组末尾移动一步 - 到开头(就像在 循环 中)时遇到了困难。例如 ['a', 'b', 'c'] 应该通过调用 .move(2,3) 变成 ['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
    };

D
Didi

作为 Reid's excellent answer 的补充(因为我无法评论);您可以使用模来使负索引和太大的索引都“翻转”:

函数 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]);返回 arr; // 用于测试 } // 返回 [2, 1, 3] console.log(array_move([1, 2, 3], 0, 1));


是的 - 由于支持负索引,我认为包装太大的索引而不是插入未定义的值似乎是明智的。
N
Naycho334
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"]

M
Mohd Abdul Baquee

var ELEMS = ['a', 'b', 'c', 'd', 'e']; /* 源项目将被移除,它会被放置在目的地之后 */ 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]); } 返回元素; } console.log('初始化:',ELEMS); var 结果 = moveItemTo('a', 'c', ELEMS); console.log('BeforeAfter:', 结果);


b
behnam

让 oldi, newi, arr; if(newi !== oldi) { 让 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(); } }


欢迎来到 SO!还有 21 个额外的答案......所以,请不要只放置代码。解释你的答案的好处。