javascript - sort - js array remove




將數組元素從一個數組位置移到另一個數組位置 (12)

我很難弄清楚如何移動一個數組元素。 例如,給定以下內容:

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

如何在'b'之前寫一個函數來移動'd' 'b'

'a' 'c'之後的'c'

移動之後,其餘元素的索引應該更新。 這意味著在移動後的第一個例子中,arr [0]會='a',arr [1] ='d'arr [2] ='b',arr [3] ='c',arr [4] = 'E'

這看起來應該很簡單,但是我無法把頭圍住。


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(','));

在這裡演示


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

一種方法是使用切片方法按照所需順序創建一個新數組。

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

你可以實現一些基本的微積分,並創建一個通用的功能,將數組元素從一個位置移動到另一個位置。

對於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”中的“移動陣列元素”。

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


如果你想在npm上使用版本, array-move是最接近這個答案的,儘管它不是相同的實現。 請參閱其用法部分了解更多詳情。 這個答案的前一個版本(修改後的Array.prototype.move)可以在npm的array.prototype.movearray.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大於數組的長度,我們希望(我假設)用新的undefined s正確地填充數組。 這個小片段通過在數組中undefined直到我們擁有合適的長度來處理這個問題。
  2. 然後,在arr.splice(old_index, 1)[0] ,我們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]

無論哪種方式,在你原來的問題中,你會做ac array_move(arr, 0, 2) 。 對於d之前的b ,你會做array_move(arr, 3, 1)


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

我喜歡這種方式。 它工作,它快速和優雅。

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

注意:一定要記得檢查你的數組邊界。


我已經根據@Merc的回答在這裡實現了一個不可變的ECMAScript 6解決方案:

const moveItemInArrayFromIndexToIndex = (array, fromIndex, toIndex) => {
  const newArray = [...array];

  if (fromIndex === toIndex) return newArray;

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

變量名稱可以縮短,只需使用長名稱,以便代碼可以自行解釋。


我結合了其中的兩種,在移動小的和大的距離時工作得更好一些。 我得到了相當一致的結果,但這可能會由比我更聰明的人做一些調整,以適應不同的尺寸等等。

移動物體時使用其他一些方法的小距離顯著快於使用拼接(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


我需要一個不可改變的移動方法(不改變原始數組),所以我修改了@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展示它的行動


這是我的一個班輪ES6解決方案,帶有一個可選參數。

Array.prototype.move = (from, to, on = 1) => {
  this.splice(to, 0, ...this.splice(from, on))
}

digiguru提出的第一個解決方案的digiguru

參數onfrom您想要移動的元素開始的元素的數量。


這裡是我在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指出,它在大型數據集上速度要慢得多。





arrays