我很难弄清楚如何移动数组中的一个元素。例如,给定以下条件:

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

我怎么能写一个函数来移动元素'd'到'b'的左边?

还是c右边的a ?

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

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

这看起来应该很简单,但我无法理解它。


当前回答

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

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)

也就是说,它依靠传播来产生一个新的副本。使用固定值3的移动会危及单个表达式的属性,或非破坏性的性质,或拼接的性能优势。同样,它更像是一个满足某些标准的示例,而不是供生产使用的建议。

其他回答

在你的例子中,因为是一个字符串数组,我们可以使用一个ranking对象来重新排列字符串数组:

let rank =  { 'a': 0, 'b': 1, 'c': 2, 'd': 0.5, 'e': 4 };
arr.sort( (i, j) => rank[i] - rank[j] );

我们可以使用这种方法来编写一个move函数,它工作在字符串数组上:

函数stringArrayMove(from, to) { 令rank = arr。Reduce ((p, c, i) => (p [c] = i, p), ({})); / /等级= {a: 0,“b”:1、“c”:2,' d ': 3,“e”:4} Rank [arr[from]] = - 0.5; / /等级= {a: 0,“b”:1、“c”:2,' d ': 1.5,“e”:4} 加勒比海盗。排序((i, j) => rank[i] - rank[j]); // arr = ['a', 'd', 'b', 'c', 'e']; } Let arr = ['a', 'b', 'c', 'd', 'e']; stringArrayMove(arr, 3,1); console.log(JSON.stringify(arr));

然而,如果我们想要排序的是一个对象数组,我们可以将排序作为每个对象的新属性,即。

let arr = [ { value: 'a', rank: 0 },
            { value: 'b', rank: 1 },
            { value: 'c', rank: 2 },
            { value: 'd', rank: 0.5 },
            { value: 'e', rank: 4 } ];
arr.sort( (i, j) => i['rank'] - j['rank'] );

我们可以使用Symbol来隐藏这个属性的可见性,即它不会在JSON.stringify中显示。我们可以在objectArrayMove函数中泛化它:

function objectArrayMove(arr, from, to) { let rank = Symbol("rank"); arr.forEach( (item, i) => item[rank] = i ); arr[from][rank] = to - 0.5; arr.sort( (i, j) => i[rank] - j[rank]); } let arr = [ { value: 'a' }, { value: 'b' }, { value: 'c' }, { value: 'd' }, { value: 'e' } ]; console.log( 'array before move: ', JSON.stringify( arr ) ); // array before move: [{"value":"a"},{"value":"b"},{"value":"c"},{"value":"d"},{"value":"e"}] objectArrayMove(arr, 3, 1); console.log( 'array after move: ', JSON.stringify( arr ) ); // array after move: [{"value":"a"},{"value":"d"},{"value":"b"},{"value":"c"},{"value":"e"}]

我需要一个不可变的移动方法(一个不改变原始数组的方法),所以我改编了@Reid的接受的答案,简单地使用对象。赋值以在进行拼接之前创建数组的副本。

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演示它的运行。

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

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

}

查看“移动数组元素”在“忧郁”的详细解释。

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

我使用不可变性助手库解决了我的问题。

import update from 'immutability-helper';

const move = (arr: any[], from: number, to: number) => update(arr, {
  $splice: [
    [from, 1],
    [to, 0, arr[from] as string],
  ],
});

const testArray = ['a', 'b', 'c', 'd', 'e'];
console.log(move(testArray, 1, 3)); // [ 'c', 'b', 'c', 'd', 'e' ]
console.log(move(testArray, 4, 0)); // [ 'e', 'b', 'c', 'd', 'a' ]

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

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)

也就是说,它依靠传播来产生一个新的副本。使用固定值3的移动会危及单个表达式的属性,或非破坏性的性质,或拼接的性能优势。同样,它更像是一个满足某些标准的示例,而不是供生产使用的建议。