Memindahkan elemen array dari satu posisi array ke posisi yang lain

522

Saya mengalami kesulitan mencari tahu cara memindahkan elemen array. Misalnya, diberikan yang berikut ini:

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

Bagaimana saya bisa menulis fungsi untuk dipindahkan 'd'sebelumnya 'b'?

Atau 'a'setelah 'c'?

Setelah pindah, indeks elemen lainnya harus diperbarui. Ini berarti dalam contoh pertama setelah langkah arr [0] akan = 'a', arr [1] = 'd' arr [2] = 'b', arr [3] = 'c', arr [4] = 'e'

Ini sepertinya cukup sederhana, tapi aku tidak bisa membungkus kepalaku.

Mark Brown
sumber
3
baik pertanyaan ini tua tapi emas
Jalal
menggunakan ES6const changeValuePosition = (arr, init, target) => {[arr[init],arr[target]] = [arr[target],arr[init]]; return arr}
muhsalaa
Itu hanya menukar elemen di initdan target.
Matt F.

Jawaban:

671

Jika Anda menginginkan versi pada npm, array-move adalah yang paling dekat dengan jawaban ini, walaupun itu bukan implementasi yang sama. Lihat bagian penggunaannya untuk lebih jelasnya. Versi sebelumnya dari jawaban ini (yang memodifikasi Array.prototype.move) dapat ditemukan pada npm di array.prototype.move .


Saya cukup sukses dengan fungsi ini:

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

Perhatikan bahwa yang terakhir returnhanya untuk tujuan pengujian: splicemelakukan operasi pada array di tempat, sehingga pengembalian tidak diperlukan. Selain itu, ini moveadalah operasi di tempat. Jika Anda ingin menghindari itu dan mengembalikan salinan, gunakan slice.

Melangkah menelusuri kode:

  1. Jika new_indexlebih besar dari panjang array, kami ingin (saya kira) untuk mengisi array dengan benar dengan yang baru undefined. Cuplikan kecil ini menangani ini dengan menekan undefinedarray sampai kita memiliki panjang yang sesuai.
  2. Lalu, dalam arr.splice(old_index, 1)[0], kita membelah elemen lama. splicemengembalikan elemen yang disambungkan, tetapi dalam array. Dalam contoh kami di atas, ini [1]. Jadi kami mengambil indeks pertama array itu untuk mendapatkan yang mentah di 1sana.
  3. Kemudian kita gunakan spliceuntuk memasukkan elemen ini di tempat new_index. Karena kami mengisi array di atas jika new_index > arr.length, mungkin akan muncul di tempat yang tepat, kecuali jika mereka telah melakukan sesuatu yang aneh seperti memasukkan angka negatif.

Versi yang lebih menarik untuk memperhitungkan indeks negatif:

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

Yang seharusnya menjelaskan hal-hal seperti array_move([1, 2, 3], -1, -2)dengan benar (pindahkan elemen terakhir ke tempat kedua ke tempat terakhir). Hasil untuk itu seharusnya [1, 3, 2].

Either way, dalam pertanyaan asli Anda, Anda akan melakukan array_move(arr, 0, 2)untuk asetelah c. Untuk dsebelumnya b, Anda akan melakukannya array_move(arr, 3, 1).

Reid
sumber
19
Ini bekerja dengan sempurna! Dan penjelasan Anda sangat jelas. Terima kasih telah meluangkan waktu untuk menulis ini.
Mark Brown
16
Anda tidak boleh memanipulasi prototipe Obyek dan Array, karena menimbulkan masalah saat mengulang elemen.
burak emre
9
@burakemre: Saya pikir kesimpulan itu tidak begitu jelas dicapai. Kebanyakan pemrogram JS yang baik (dan pustaka paling populer) akan menggunakan tanda .hasOwnPropertycentang ketika mengulangi hal-hal seperti untuk..di, terutama dengan pustaka seperti Prototipe dan MooTools yang memodifikasi prototipe. Bagaimanapun, saya tidak merasa itu adalah masalah yang sangat penting dalam contoh yang relatif terbatas seperti ini, dan ada perpecahan yang bagus di komunitas mengenai apakah modifikasi prototipe adalah ide yang baik atau tidak. Namun, biasanya masalah iterasi adalah yang paling tidak diperhatikan.
Reid
3
Tidak perlu untuk loop pada langkah 1, Anda cukup menggunakan this[new_index] = undefined;dalam ifblok. Karena array Javascript jarang, ini akan memperluas ukuran array untuk memasukkan new_index .spliceagar berfungsi tetapi tanpa perlu membuat elemen apa pun yang campur tangan.
Michael
3
@Michael: Poin bagus - tetapi melakukan this[new_index] = undefinedakan benar-benar menempatkan undefinedslot array sebelum indeks yang benar. (Misalnya, [1,2,3].move(0,10)akan ada 1di slot 10 dan undefineddi slot 9.) Sebaliknya, jika sparseness baik-baik saja, kita bisa melakukannya this[new_index] = this.splice(old_index, 1)[0]tanpa panggilan splice lainnya (sebagai gantinya / kalau bukan).
Reid
268

Inilah satu liner yang saya temukan di JSPerf ....

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

yang mengagumkan untuk dibaca, tetapi jika Anda ingin kinerja (dalam set data kecil) coba ...

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

Saya tidak bisa mengambil kredit apa pun, itu semua harus ke Richard Scarrott . Ini mengalahkan metode berbasis sambatan untuk set data yang lebih kecil dalam tes kinerja ini . Namun secara signifikan lebih lambat pada set data yang lebih besar seperti yang ditunjukkan Darwayne .

digiguru
sumber
2
Solusi Anda yang lebih berkinerja lebih lambat pada kumpulan data besar. jsperf.com/array-prototype-move/8
Darwayne
44
Ini sepertinya perdagangan yang sangat konyol. Kinerja pada set data kecil adalah keuntungan yang dapat diabaikan, tetapi kerugian pada set data besar adalah kerugian yang signifikan. Pertukaran bersih Anda negatif.
Kyeotic
3
@ Reid Itu bukan keharusan. IMO tidak apa-apa untuk mengasumsikan bahwa panjang array tidak bisa dimodifikasi.
robsch
3
Satu solusi garis perlu menangani dua situasi:from >= to ? this.splice(to, 0, this.splice(from, 1)[0]) : this.splice(to - 1, 0, this.splice(from, 1)[0]);
Rob L
13
Harap jangan pernah memodifikasi prototipe bawaan. nczonline.net/blog/2010/03/02/...
LJHarb
231

Saya suka cara ini. Ini ringkas dan berhasil.

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

Catatan: selalu ingat untuk memeriksa batas array Anda.

Jalankan Cuplikan di jsFiddle

SteakOverflow
sumber
29
Karena Array.splice mengembalikan nilai yang dihapus dalam Array baru, Anda dapat menuliskannya sebagai satu liner ... arr.splice (indeks + 1, 0, arr.splice (indeks, 1) [0]);
Eric
49
Secara pribadi saya lebih suka kode 3 baris. Lebih mudah dipahami: Dapatkan salinan elemen; hapus dari array; masukkan di posisi baru. Satu liner lebih pendek tetapi tidak begitu jelas untuk dipahami orang lain ...
Philipp
2
Kode pendek dan sederhana. Tapi ini 2019 !!, Buat klon dari array dan kembalikan itu bukan bermutasi array. Ini akan membuat fungsi Anda "arraymove" memenuhi standar pemrograman fungsional
SamwellTarly
4
OK tapi tidak semuanya baik adalah juga harus fungsional pemrograman compliant; ditambah ini masih dapat berguna dalam pemrograman fungsional di dalam prosedur untuk memanipulasi array lokal.
SteakOverflow
36

Metode splice () menambah / menghapus item ke / dari array, dan mengembalikan item yang dihapus .

Catatan: Metode ini mengubah array asli. / w3sekolah /

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

karena fungsi ini dapat dihubungkan, ini juga berfungsi:

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

demo di sini


sumber
Apakah ada perpustakaan yang menggunakan ini? Cukup rapi!
uicoded
Lihat komentar lain tentang ini: ide buruk untuk memodifikasi prototipe bawaan seperti Array dan Object. Anda akan merusak barang-barang.
geoidesic
27

2c saya Mudah dibaca, bekerja, cepat, tidak membuat array baru.

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;
}
Merc
sumber
2
Pada fungsi string pertama Anda harus kembali array, seperti yang dilakukan di akhir.
Sergey Voronezhskiy
3
Benar bagaimana saya merindukan itu? Tetap!
Merc
Saya paling suka solusi sederhana dan fleksibel Anda. Terima kasih!
Roman M. Koss
18

Mendapat ide ini dari @ Reid mendorong sesuatu di tempat item yang seharusnya dipindahkan untuk menjaga ukuran array konstan. Itu memang menyederhanakan perhitungan. Juga, mendorong objek kosong memiliki manfaat tambahan karena dapat mencarinya secara unik nanti. Ini berfungsi karena dua objek tidak sama sampai mereka merujuk ke objek yang sama.

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

Jadi, inilah fungsi yang mengambil dalam array sumber, dan sumber, indeks tujuan. Anda dapat menambahkannya ke Array.prototype jika diperlukan.

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);
}
Anurag
sumber
1
Ini terlihat menjanjikan ... dan saya tidak tahu tentang perbandingan javascript js. Terima kasih!
Mark Brown
Tidak berfungsi untuk kasus sourceIndex = 0,destIndex = 1
Sergey Voronezhskiy
destIndexdimaksudkan sebagai indeks sebelum elemen sumber dipindahkan dalam array.
Anurag
Ini adalah jawaban terbaik sejauh ini. Jawaban lain gagal beberapa unit test di suite saya (bergerak maju)
Ilya Ivanov
16

Ini didasarkan pada solusi @ Reid. Kecuali:

  • Saya tidak mengubah Arrayprototipe.
  • Memindahkan item di luar batas ke kanan tidak membuat undefineditem, itu hanya memindahkan item ke posisi paling kanan.

Fungsi:

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

Tes unit:

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);
    });
});
André Pena
sumber
ini salah, jika Anda memasukkan posisi posting, indeks akan berubah karena Anda telah menghapus item
Yao Zhao
Terima kasih. Saya ingin menghapus item dari array tanpa meninggalkan elemen nol (yang terjadi saat menggunakan splice (indexToRemove). Saya menggunakan metode Anda untuk memindahkan item yang ingin saya hapus ke akhir array, dan kemudian menggunakan pop () metode untuk menghapus.
Luke Schoen
suka fitur "pindahkan item ke posisi paling kanan", berguna untuk kasus saya. thx
bFunc
11

Berikut ini adalah solusi ES6 one liner saya dengan parameter opsional on.

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

Adaptasi solusi pertama yang diusulkan oleh digiguru

Parameter onadalah jumlah elemen mulai dari fromyang ingin Anda pindahkan.

Elie Teyssedou
sumber
Solusinya baik-baik saja. Namun, ketika Anda memperluas prototipe Anda tidak boleh menggunakan fungsi panah karena dalam hal ini 'ini' bukan contoh array tetapi misalnya objek Window.
wawka
7

The splicemetode Arraykekuatan bantuan: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice

Hanya perlu diingat bahwa itu mungkin relatif mahal karena harus secara aktif mengindeks ulang array.

Ken Franqueiro
sumber
Yap, tetapi segera setelah saya melakukan sambungan, indeks array diperbarui, yang menyulitkan saya untuk mencari tahu di mana harus menempatkan elemen yang baru saja saya hapus. Terutama karena saya membutuhkan fungsi untuk dapat menangani gerakan di kedua arah.
Mark Brown
@ Mark: jangan menyambungkan string dan menyimpannya ke variabel yang sama, buat string baru dan sambungkan itu. Lihat jawaban saya di bawah ini.
Jared Updike
7

Salah satu pendekatan akan membuat array baru dengan potongan-potongan dalam urutan yang Anda inginkan, menggunakan metode slice.

Contoh

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) memberi Anda ['a']
  • arr.slice (2,4) memberi Anda ['b', 'c']
  • arr.slice (4) memberi Anda ['e']
Jared Updike
sumber
1
Anda benar-benar menyadari bahwa pada arr2akhirnya Anda adalah sebuah string karena operasi penggabungan, kan? :) Akhirnya menjadi "adc,de".
Ken Franqueiro
6

Anda dapat menerapkan beberapa Kalkulus dasar dan membuat fungsi universal untuk memindahkan elemen array dari satu posisi ke posisi lain.

Untuk JavaScript tampilannya seperti ini:

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; 

}

Lihat "elemen array yang bergerak" di "gloommatter" untuk penjelasan terperinci.

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

Andrea
sumber
1
Ini seharusnya menjadi jawaban yang benar, karena tidak mengalokasikan array baru. Terima kasih!
Cᴏʀʏ
Tautan rusak.
Rokit
6

Saya telah menerapkan ECMAScript 6solusi yang tidak dapat diubah berdasarkan dari @Mercjawaban di sini:

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

Nama-nama variabel dapat disingkat, hanya digunakan yang panjang sehingga kode dapat menjelaskan sendiri.

Barry Michael Doyle
sumber
jelas jawaban yang lebih baik, mutasi menciptakan efek samping
Matt Lo
1
Karena penasaran, mengapa tidak arraysegera kembali jika fromIndex === toIndex, dan hanya membuat newArrayjika tidak demikian? Kekekalan tidak berarti bahwa satu salinan baru harus dibuat per panggilan fungsi bahkan ketika tidak ada perubahan. Hanya meminta b / c motif untuk peningkatan panjang fungsi ini (relatif terhadap one-liner berbasis splice) adalah kinerja, dan fromIndexmungkin sering sama toIndex, tergantung pada penggunaan.
Robert Monfera
5

Saya membutuhkan metode bergerak yang tidak berubah (yang tidak mengubah array asli), jadi saya mengadaptasi jawaban yang diterima @ Reid untuk hanya menggunakan Object.assign untuk membuat salinan array sebelum melakukan sambungan.

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

Berikut adalah jsfiddle yang menunjukkannya dalam aksi .

Javid Jamae
sumber
Itu selalu baik untuk melihat ppl mempertimbangkan mutasi.
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

Arthur Tsidkilov
sumber
2

Saya akhirnya menggabungkan dua ini untuk bekerja sedikit lebih baik ketika memindahkan jarak kecil dan besar. Saya mendapatkan hasil yang cukup konsisten, tetapi ini mungkin bisa sedikit diubah oleh seseorang yang lebih pintar daripada saya untuk bekerja secara berbeda untuk ukuran yang berbeda, dll.

Menggunakan beberapa metode lain saat memindahkan objek jarak kecil secara signifikan lebih cepat (x10) daripada menggunakan sambungan. Ini mungkin berubah tergantung pada panjang array, tetapi itu berlaku untuk array besar.

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

Andrew Backer
sumber
2

Ini dinyatakan di banyak tempat ( menambahkan fungsi kustom ke dalam Array.prototype ) bermain dengan prototipe Array bisa menjadi ide yang buruk, toh saya menggabungkan yang terbaik dari berbagai posting, saya datang dengan ini, menggunakan Javascript modern:

    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

Semoga bisa bermanfaat bagi siapa saja

BernieSF
sumber
2

Versi ini tidak ideal untuk semua tujuan, dan tidak semua orang suka ekspresi koma, tapi ini satu-liner yang merupakan ekspresi murni, membuat salinan baru:

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

Versi yang sedikit ditingkatkan kinerja akan mengembalikan array input jika tidak diperlukan langkah apa pun, itu masih OK untuk penggunaan yang tidak dapat diubah, karena array tidak akan berubah, dan itu masih ekspresi murni:

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

Doa keduanya adalah

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

yaitu mengandalkan penyebaran untuk menghasilkan salinan baru. Menggunakan arity tetap 3 moveakan membahayakan properti ekspresi tunggal, atau sifat non-destruktif, atau manfaat kinerja splice. Sekali lagi, ini lebih merupakan contoh yang memenuhi beberapa kriteria daripada saran untuk penggunaan produksi.

Robert Monfera
sumber
1

Array.move.js

Ringkasan

Memindahkan elemen dalam array, mengembalikan array yang mengandung elemen yang dipindahkan.

Sintaksis

array.move(index, howMany, toIndex);

Parameter

index : Indeks tempat memindahkan elemen. Jika negatif, indeks akan mulai dari akhir.

howMany : Jumlah elemen untuk dipindahkan dari indeks .

toIndex : Indeks array tempat menempatkan elemen yang dipindahkan. Jika negatif, toIndex akan mulai dari akhir.

Pemakaian

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;
    }
});
Jonathan Neal
sumber
2
Sementara .movesepertinya itu harus bekerja (saya belum mengujinya), Anda harus mencatat bahwa itu bukan bagian dari standar apa pun. Ini juga baik untuk memperingatkan orang-orang bahwa fungsi polyfill / monkeypatched dapat memecahkan beberapa kode yang menganggap semua yang dapat dihitung adalah milik mereka.
Jeremy J Starcher
1
a = ["a", "b", "c"]; a.move (0,1,1); // a = ["a", "b", "c"], harus menjadi ["b", "a", "c"]
Leonard Pauli
2
Fitur ini sudah usang dan mungkin tidak didukung lagi. Hati-hati Lihat: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Mostafa
1

Saya menggunakan jawaban yang bagus dari @Reid , tetapi berjuang dengan memindahkan elemen dari akhir array satu langkah lebih jauh - ke awal (seperti dalam satu lingkaran ). Misalnya ['a', 'b', 'c'] harus menjadi ['c', 'a', 'b'] dengan memanggil .move (2,3)

Saya mencapai ini dengan mengubah case untuk 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
    };
Marcel Böttcher
sumber
1

Sebagai tambahan untuk jawaban luar biasa Reid (dan karena saya tidak bisa berkomentar); Anda dapat menggunakan modulo untuk membuat indeks negatif dan terlalu besar "berguling":

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

Didi
sumber
Ya - karena indeks negatif didukung, tampaknya masuk akal untuk membungkus indeks terlalu besar daripada memasukkan nilai yang tidak ditentukan, menurut pendapat saya.
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)

Shijo Rs
sumber
1

Saya pikir ini masalah swap tetapi tidak. Inilah solusi satu-liner saya:

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

Inilah tes kecil:

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' ]
cagdas_ucar
sumber
Nah, pertanyaannya bukan tentang menukar item. Penulis meminta solusi untuk strategi memasukkan.
Andreas Dolk
Sehubungan dengan pertanyaan yang ada, ini adalah jawaban yang salah secara objektif.
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 );

hasil:

["b", "a", "c", "d"]
Naycho334
sumber
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();
      }
    }

behnam
sumber
1
Selamat datang di SO! Ada 21 jawaban tambahan ... jadi, tolong, jangan hanya kode tempat. Jelaskan manfaat dari jawaban Anda.
David García Bodego
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);

Mohd Abdul Baquee
sumber
0

Versi tidak berubah tanpa salinan array:

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

Saya pikir cara terbaik adalah mendefinisikan properti baru untuk Array

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]
iProDev
sumber
0

Varian JS murni lainnya menggunakan operator spread array ES6 tanpa mutasi

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

abr
sumber
0

Metode ini akan mempertahankan array asli, dan memeriksa kesalahan pembatas.

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}
nikk wong
sumber