Elemen array swap Javascript

228

Apakah ada cara yang lebih sederhana untuk menukar dua elemen dalam array?

var a = list[x], b = list[y];
list[y] = a;
list[x] = b;
ken
sumber

Jawaban:

412

Anda hanya perlu satu variabel sementara.

var b = list[y];
list[y] = list[x];
list[x] = b;

Edit pembajakan jawaban teratas 10 tahun kemudian dengan banyak adopsi ES6 di bawah ikat pinggang kami:

Dengan array yang diberikan arr = [1,2,3,4], Anda dapat menukar nilai dalam satu baris sekarang seperti:

[arr[0], arr[1]] = [arr[1], arr[0]];

Ini akan menghasilkan array [2,1,3,4]. Ini adalah tugas yang merusak .

tvanfosson
sumber
2
Bahkan tanpa menggunakan ECMAScript 6 Destructure Assignment, sebenarnya dapat mencapai swap simultan tanpa mencemari ruang lingkup saat ini dengan variabel sementara: a = [b, b = a][0];seperti yang ditunjukkan oleh @Jan Meskipun saya masih menemukan diri saya menggunakan pendekatan variabel sementara karena itu lintas-bahasa (misalnya C / C ++ ) dan pendekatan pertama yang biasanya muncul di pikiran saya.
Ultimater
3
Anda dapat bertukar di tempat (bermutasi) dengan es6 seperti yang orang lain tunjukkan di bawah ini:[ list[y], list[x] ] = [ list[x], list[y] ];
protoEvangelion
[arr[0], arr[1]] = [arr[1], arr[0]]hanya menghasilkan [2, 1]tanpa sisa array
Yerko Palma
8
@YerkoPalma - ekspresi kembali [2,1], tetapi array asli akan dimutasi menjadi [2,1,3,4]
danbars
111

Jika Anda ingin ekspresi tunggal, menggunakan javascript asli, ingat bahwa nilai kembali dari operasi splice berisi elemen yang telah dihapus.

var A = [1, 2, 3, 4, 5, 6, 7, 8, 9], x= 0, y= 1;
A[x] = A.splice(y, 1, A[x])[0];
alert(A); // alerts "2,1,3,4,5,6,7,8,9"

Edit:

The [0]diperlukan pada akhir ekspresi sebagai Array.splice()hasil array, dan dalam situasi ini kita memerlukan satu elemen dalam array kembali.

kennebec
sumber
3
sambatan mengembalikan array. Jadi dalam contoh Anda, setelah operasi swap array Anda benar-benar terlihat seperti: [[2], 1, 3, 4, 5, 6, 7, 8, 9]
JPot
1
A [x] = A.splice (y, 1, A [x]) [0]; ? di mootools Array.implement ({swap: function (x, y) {this [y] = this.splice (x, 1, this [y]) [0];}});
ken
Dikonfirmasi, [0] tidak ada.
Johann Philipp Strathausen
bagus dan pendek, tetapi seperti yang dikatakan @aelgoa, pertukaran yang lambat dan sederhana
ofir_aghai
75

Ini sepertinya ok ....

var b = list[y];
list[y] = list[x];
list[x] = b;

Howerver menggunakan

var b = list[y];

berarti variabel b akan hadir untuk sisa ruang lingkup. Ini berpotensi menyebabkan kebocoran memori. Tidak mungkin, tetapi masih lebih baik untuk dihindari.

Mungkin ide yang bagus untuk memasukkan ini ke dalam Array.prototype.swap

Array.prototype.swap = function (x,y) {
  var b = this[x];
  this[x] = this[y];
  this[y] = b;
  return this;
}

yang bisa disebut seperti:

list.swap( x, y )

Ini adalah pendekatan yang bersih untuk menghindari kebocoran memori dan KERING .

Stefan
sumber
Saya juga suka ini. Array. implement ({swap: function (x, y) {x = this [x]; this [x] = this [y]; this [y] = x; kembalikan ini;}});
ken
1
Ini bagus. Mungkin beberapa batasan memeriksa? Array.prototype.swap = function (x,y) { if (x >= 0 && x < this.length && y >= 0 && y < this.length) { var b = this[x]; this[x] = this[y]; this[y] = b; } return this; };
David R.
@ DavidR. Pengecekan batas tidak perlu dan tidak perlu. Penelepon memiliki semua yang diperlukan untuk melakukan pemeriksaan seperti itu jika diinginkan, meskipun dalam kebanyakan kasus Anda sudah tahu x dan y berada dalam batas karena Anda berada dalam lingkaran semacam itu.
Neil
6
Tidak bisakah Anda menghindari "potensi kebocoran memori" dengan hanya membungkusnya dalam suatu fungsi?
Carcigenicate
3
Untuk menghindari kecelakaan "ratakan" potensial, saya tidak akan menyentuh rantai prototipe tipe bawaan apa pun.
AaronDancer
55

Menurut beberapa orang acak di Metafilter , "Versi Javascript terbaru memungkinkan Anda melakukan swap (antara lain) jauh lebih rapi:"

[ list[x], list[y] ] = [ list[y], list[x] ];

Tes cepat saya menunjukkan bahwa kode Pythonic ini berfungsi dengan baik dalam versi JavaScript yang saat ini digunakan di "Google Apps Script" (".gs"). Sayangnya, tes lebih lanjut menunjukkan kode ini memberikan "Uncaught ReferenceError: sisi kiri tidak valid dalam penugasan." dalam versi apa pun JavaScript (".js") digunakan oleh Google Chrome Versi 24.0.1312.57 m.

David Cary
sumber
2
Ini adalah bagian dari proposal ES6: itu belum diformalkan, jadi itu seharusnya tidak benar-benar dianggap bekerja di mana-mana (itu akan luar biasa jika memang ...).
Isiah Meadows
2
Ini bekerja di versi terbaru firefox saat ini (39.0.3).
Jamie
2
Ini bekerja di Versi Chrome 54.0.2840.71 dan Versi sebelumnya. Juga, ini harus menjadi kode Anda jika Anda menggunakan transpiler ES6 seperti babel .
amoebe
3
Cintai solusi ini. Bersihkan, sebagaimana dimaksud. Sayang sekali pertanyaan itu ditanyakan 9 tahun lalu ...
DavidsKanal
2
itu telah distandarisasi dalam es6 dan fitur ini disebut destrukturisasi.
AL-zami
29

Nah, Anda tidak perlu buffer kedua nilai - hanya satu:

var tmp = list[x];
list[x] = list[y];
list[y] = tmp;
Marc Gravell
sumber
13
'tmp' Anda terdengar lebih masuk akal untuk digunakan kemudian 'b'
mtasic85
@ofir_aghai ya, Anda benar: 10+ tahun yang lalu, jawaban lain telah diposting 22 detik sebelum yang ini (12: 14: 16Z vs 12: 14: 38Z) ...
Marc Gravell
di hari biasa, saya tetap dengan itu. tetapi hanya karena masalah detik & rasa hormat dari 10 tahun Anda melanjutkan di sini ;-)
ofir_aghai
maaf itu tidak memungkinkan saya untuk mengubah suara .. "
Suara
22

Anda bisa menukar elemen dalam array dengan cara berikut:

list[x] = [list[y],list[y]=list[x]][0]

Lihat contoh berikut:

list = [1,2,3,4,5]
list[1] = [list[3],list[3]=list[1]][0]
//list is now [1,4,3,2,5]

Catatan: ini bekerja dengan cara yang sama untuk variabel biasa

var a=1,b=5;
a = [b,b=a][0]
Jan
sumber
6
Hal ini sangat mirip dengan cara yang benar standar untuk melakukan hal ini di ES6 (versi berikutnya dari JavaScript): [list[x], list[y]] = [list[y], list[x]];.
Isiah Meadows
1
Ini tidak ada hubungannya dengan kita menukar array ES6 dengan de-structuring. Ini hanya penggunaan alur kerja JS yang cerdas. Pola swap yang indah jika Anda sering menggunakan inline coding, sepertithis[0] > this[1] && (this[0] = [this[1],this[1]=this[0]][0]);
Redu
18

Dengan nilai numerik Anda dapat menghindari variabel sementara dengan menggunakan bitwise xor

list[x] = list[x] ^ list[y];
list[y] = list[y] ^ list[x];
list[x] = list[x] ^ list[y];

atau jumlah aritmatika (mencatat bahwa ini hanya berfungsi jika x + y kurang dari nilai maksimum untuk tipe data)

list[x] = list[x] + list[y];
list[y] = list[x] - list[y];
list[x] = list[x] - list[y];
Jakub Arnold
sumber
2
Apakah darth itu seperti di vader? +1
krosenvold
7
Sesuatu yang salah. Tidak list[y] = list[x] - list[x];hanya menyamakan list[y] = 0;?
ErikE
3
Trik xor juga gagal ketika x = y - itu mengatur daftar [x] menjadi nol, ketika Anda mungkin mengharapkannya untuk menyimpan daftar [x] nilai asli.
David Cary
1
Secara teknis Anda membuat nilai temporer Anda hanya tidak memindahkannya di luar area yang relevan dari array.
Mark Smit
1
Tidak sederhana, tidak lebih efisien, tidak juga generik.
LoganMzz
17

Ini tidak ada ketika pertanyaan diajukan, tetapi ES2015 memperkenalkan perusakan array, memungkinkan Anda untuk menulisnya sebagai berikut:

let a = 1, b = 2;
// a: 1, b: 2
[a, b] = [b, a];
// a: 2, b: 1
dirkdig
sumber
14
Untuk bertukar seperti ini di dalam array:[list[x], list[y]] = [list[y], list[x]];
Stromata
15

Untuk menukar dua elemen array berturut-turut

array.splice(IndexToSwap,2,array[IndexToSwap+1],array[IndexToSwap]);
Piyush Madan
sumber
13

Intisari dari http://www.greywyvern.com/?post=265

var a = 5, b = 9;    
b = (a += b -= a) - b;    
alert([a, b]); // alerts "9, 5"
R-arah Orz
sumber
1
Jika Anda membungkus ini dalam suatu swap(a, b)fungsi Anda tidak perlu khawatir tentang keterbacaan.
AccidentalTaylorExpansion
1
Hanya berfungsi untuk bilangan bulat
Redu
Ini mungkin kurang optimal. Kompiler mungkin mendeteksinya sebagai "swap idiom", tetapi tidak dapat memastikan efeknya kecuali dapat memastikan bahwa kedua tipe int, dan juga tidak alias .
mwfearnley
10

bagaimana dengan Destructure_assignment

var arr = [1, 2, 3, 4]
[arr[index1], arr[index2]] = [arr[index2], arr[index1]]

yang juga dapat diperpanjang ke

[src order elements] => [dest order elements]
ROROROOROROR
sumber
9

Pertimbangkan solusi seperti itu tanpa perlu mendefinisikan variabel ketiga:

function swap(arr, from, to) {
  arr.splice(from, 1, arr.splice(to, 1, arr[from])[0]);
}

var letters = ["a", "b", "c", "d", "e", "f"];

swap(letters, 1, 4);

console.log(letters); // ["a", "e", "c", "d", "b", "f"]

Catatan: Anda mungkin ingin menambahkan cek tambahan misalnya untuk panjang array. Solusi ini bisa berubah sehingga swapfungsi tidak perlu mengembalikan array baru, itu hanya mutasi over array yang dilewatkan.

Shevchenko Viktor
sumber
Sebagai tambahan, operator spread juga dapat digunakan:arr.splice(from, 1, arr.splice(to, 1, ...arr[from]))
Orkun Tuzel
7

Anda dapat menukar sejumlah objek atau literal, bahkan dari jenis yang berbeda, menggunakan fungsi identitas sederhana seperti ini:

var swap = function (x){return x};
b = swap(a, a=b);
c = swap(a, a=b, b=c);

Untuk masalah Anda:

var swap = function (x){return x};
list[y]  = swap(list[x], list[x]=list[y]);

Ini berfungsi dalam JavaScript karena ia menerima argumen tambahan meskipun tidak dideklarasikan atau digunakan. Penugasan a=bdll, terjadi setelah aditeruskan ke fungsi.

dansalmo
sumber
Hackish ... tapi Anda bisa melakukan yang lebih baik, jika Anda hanya menggunakan fungsi sekali: list[y] = (function(x){return x})(list[x],list[x]=list[y]);. Atau, jika Anda tertarik dengan ES6 (versi JS berikutnya), ini sangat mudah:[list[x], list[y]] = [list[y], list[x] . Saya sangat senang mereka menambahkan beberapa aspek yang lebih fungsional dan berbasis kelas ke dalam versi JavaScript berikutnya.
Isiah Meadows
6

Untuk dua atau lebih elemen (nomor tetap)

[list[y], list[x]] = [list[x], list[y]];

Tidak diperlukan variabel sementara!

Saya sedang berpikir tentang sekadar menelepon list.reverse().
Tapi kemudian saya menyadari itu akan berfungsi sebagai swap hanya ketika list.length = x + y + 1.

Untuk jumlah elemen yang bervariasi

Saya telah melihat berbagai konstruksi Javascript modern untuk efek ini, termasuk Peta dan peta , tetapi sayangnya tidak ada yang menghasilkan kode yang lebih kompak atau lebih cepat daripada konstruksi berbasis loop yang kuno:

function multiswap(arr,i0,i1) {/* argument immutable if string */
    if (arr.split) return multiswap(arr.split(""), i0, i1).join("");
    var diff = [];
    for (let i in i0) diff[i0[i]] = arr[i1[i]];
    return Object.assign(arr,diff);
}

Example:
    var alphabet = "abcdefghijklmnopqrstuvwxyz";
    var [x,y,z] = [14,6,15];
    var output = document.getElementsByTagName("code");
    output[0].innerHTML = alphabet;
    output[1].innerHTML = multiswap(alphabet, [0,25], [25,0]);
    output[2].innerHTML = multiswap(alphabet, [0,25,z,1,y,x], [25,0,x,y,z,3]);
<table>
    <tr><td>Input:</td>                        <td><code></code></td></tr>
    <tr><td>Swap two elements:</td>            <td><code></code></td></tr>
    <tr><td>Swap multiple elements:&nbsp;</td> <td><code></code></td></tr>
</table>

7vujy0f0hy
sumber
5

Ada satu cara yang menarik untuk bertukar:

var a = 1;
var b = 2;
[a,b] = [b,a];

(Cara ES6)

Vivek
sumber
5
untuk sebuah array, ini lebihvar a= [7,8,9,10], i=2, j=3;[a[i],a[j]] = [a[j],a[i]];
caub
4
var a = [1,2,3,4,5], b=a.length;

for (var i=0; i<b; i++) {
    a.unshift(a.splice(1+i,1).shift());
}
a.shift();
//a = [5,4,3,2,1];
Nathan Romano
sumber
3

Berikut adalah satu-liner yang tidak bermutasi list:

let newList = Object.assign([], list, {[x]: list[y], [y]: list[x]})

(Menggunakan fitur bahasa tidak tersedia pada 2009 ketika pertanyaan diposting!)

fmg
sumber
1

Berikut ini adalah nilai swap versi kompak di i1 dengan i2 di arr

arr.slice(0,i1).concat(arr[i2],arr.slice(i1+1,i2),arr[i1],arr.slice(i2+1))
pengguna2044802
sumber
Itu kurang efisien daripada metode variabel sementara. Anda secara efektif mengembalikan array yang dimodifikasi yang diiris tiga kali dan digabungkan bersama dengan dua objek di antara tiga array yang diiris. Anda telah secara efektif membutuhkan lebih dari dua kali memori daripada yang diperlukan untuk mendapatkan nilai hanya dengan menetapkan ke array (tidak ada yang dilakukan di tempat).
Isiah Meadows
1

Berikut adalah variasi yang pertama memeriksa apakah indeks ada dalam array:

Array.prototype.swapItems = function(a, b){
    if(  !(a in this) || !(b in this) )
        return this;
    this[a] = this.splice(b, 1, this[a])[0];
    return this;
}

Saat ini hanya akan kembali thisjika indeks tidak ada, tetapi Anda dapat dengan mudah mengubah perilaku gagal

Douglas.Sesar
sumber
1

Tukar elemen pertama dan terakhir dalam array tanpa metode swap variabel atau ES6 sementara [a, b] = [b, a]

[a.pop(), ...a.slice(1), a.shift()]

gengns
sumber
1

Solusi skrip yang mengkloning larik alih-alih mengubah yang sudah ada

export function swapItemsInArray<T>(items: T[], indexA: number, indexB: number): T[] {
  const itemA = items[indexA];

  const clone = [...items];

  clone[indexA] = clone[indexB];
  clone[indexB] = itemA;

  return clone;
}
pie6k
sumber
0

Hanya untuk bersenang-senang, cara lain tanpa menggunakan variabel tambahan adalah:

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];

// swap index 0 and 2
arr[arr.length] = arr[0];   // copy idx1 to the end of the array
arr[0] = arr[2];            // copy idx2 to idx1
arr[2] = arr[arr.length-1]; // copy idx1 to idx2
arr.length--;               // remove idx1 (was added to the end of the array)


console.log( arr ); // -> [3, 2, 1, 4, 5, 6, 7, 8, 9]

vsync
sumber
0

Demi singkatnya, inilah versi one-liner jelek yang hanya sedikit kurang jelek dari semua yang concat dan mengiris di atas. Jawaban yang diterima benar-benar cara untuk pergi dan jauh lebih mudah dibaca.

Diberikan:

var foo = [ 0, 1, 2, 3, 4, 5, 6 ];

jika Anda ingin menukar nilai dua indeks (a dan b); maka ini akan melakukannya:

foo.splice( a, 1, foo.splice(b,1,foo[a])[0] );

Misalnya, jika Anda ingin menukar 3 dan 5, Anda bisa melakukannya dengan cara ini:

foo.splice( 3, 1, foo.splice(5,1,foo[3])[0] );

atau

foo.splice( 5, 1, foo.splice(3,1,foo[5])[0] );

Keduanya menghasilkan hasil yang sama:

console.log( foo );
// => [ 0, 1, 2, 5, 4, 3, 6 ]

#splicehatersarepunks :)

Jasonovich
sumber
0

Jika Anda tidak ingin menggunakan variabel temp di ES5, ini adalah salah satu cara untuk menukar elemen array.

var swapArrayElements = function (a, x, y) {
  if (a.length === 1) return a;
  a.splice(y, 1, a.splice(x, 1, a[y])[0]);
  return a;
};

swapArrayElements([1, 2, 3, 4, 5], 1, 3); //=> [ 1, 4, 3, 2, 5 ]
venkat7668
sumber
Dengan cara ini, alih-alih membuat variabel temp, Anda membuat 2 array baru sebagai a.splicemengembalikan array dengan elemen yang dihapus. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
XCS
Apakah ada cara agar kita dapat melakukannya dengan lebih baik? @Cristy
venkat7668
Jawaban yang diterima langsung ke depan. Ini akan berguna ketika Anda memiliki batasan pada jumlah deklarasi variabel (kebanyakan tujuan wawancara :)). Tapi memori tidak efisien seperti yang Anda sebutkan. @Cristy
venkat7668
Saya pribadi berpikir ini adalah praktik yang buruk dan tidak disarankan untuk pemula. Ini juga sangat sulit dibaca.
XCS
0

coba fungsi ini ...

$(document).ready(function () {
        var pair = [];
        var destinationarray = ['AAA','BBB','CCC'];

        var cityItems = getCityList(destinationarray);
        for (var i = 0; i < cityItems.length; i++) {
            pair = [];
            var ending_point = "";
            for (var j = 0; j < cityItems[i].length; j++) {
                pair.push(cityItems[i][j]);
            }
            alert(pair);
            console.log(pair)
        }

    });
    function getCityList(inputArray) {
        var Util = function () {
        };

        Util.getPermuts = function (array, start, output) {
            if (start >= array.length) {
                var arr = array.slice(0);
                output.push(arr);
            } else {
                var i;

                for (i = start; i < array.length; ++i) {
                    Util.swap(array, start, i);
                    Util.getPermuts(array, start + 1, output);
                    Util.swap(array, start, i);
                }
            }
        }

        Util.getAllPossiblePermuts = function (array, output) {
            Util.getPermuts(array, 0, output);
        }

        Util.swap = function (array, from, to) {
            var tmp = array[from];
            array[from] = array[to];
            array[to] = tmp;
        }
        var output = [];
        Util.getAllPossiblePermuts(inputArray, output);
        return output;
    }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

bilal chaudhari
sumber
0

var arr = [1, 2];
arr.splice(0, 2, arr[1], arr[0]);
console.log(arr); //[2, 1]

JATIN KUMAR NAYAK
sumber
1
Sementara potongan kode ini dapat menyelesaikan pertanyaan, termasuk penjelasan sangat membantu untuk meningkatkan kualitas posting Anda. Ingatlah bahwa Anda menjawab pertanyaan untuk pembaca di masa depan, dan orang-orang itu mungkin tidak tahu alasan untuk saran kode Anda.
Alessio
-1

Menggunakan ES6 dimungkinkan untuk melakukannya seperti ini ...

Bayangkan Anda memiliki 2 array ini ...

const a = ["a", "b", "c", "d", "e"];
const b = [5, 4, 3, 2, 1];

dan Anda ingin menukar nilai pertama:

const [a0] = a;
a[0] = b[0];
b[0] = a0;

dan nilai:

a; //[5, "b", "c", "d", "e"]
b; //["a", 4, 3, 2, 1]
Alireza
sumber
-2
Array.prototype.swap = function(a, b) {
  var temp = this[a];
  this[a] = this[b];
  this[b] = temp;
};

Pemakaian:

var myArray = [0,1,2,3,4...];
myArray.swap(4,1);
pengguna2472643
sumber
1
Tidak perlu kasar. Juga, memperluas Arrayprototipe bukan bagian dari apa yang diminta - mungkin membingungkan lebih dari itu tidak baik.
Mathias Lykkegaard Lorenzen
Bagaimana menyatakan bahwa beberapa jawaban gila dan memperluas prototipe array akan dan menambahkan pengembalian ini akan membuatnya berantai ...
user2472643
2
Anda menyatakannya sebagai "cara yang benar". Mungkin memberi kesan yang salah. Sebagai gantinya, saya akan menyarankan menyebutkan apa yang Anda lakukan (memperluas prototipe), dan bagaimana itu berguna, persis seperti yang baru saja Anda jelaskan kepada saya.
Mathias Lykkegaard Lorenzen
1
Gotcha, maaf poise saya tidak pada pasangan kadang-kadang ^ _ ^
user2472643
2
Anda adalah satu-satunya yang menjelaskan masalah dengan konteks jawaban ... pertama, skor negatif harus disediakan untuk jawaban yang tidak berfungsi. Kedua ini adalah jawaban yang bagus dengan penggunaan yang elegan yang tidak menyebabkan konflik. Nilai kodenya bukan kirimannya. Juga dalam jawaban saya jika Anda menghapusnya dan mengecualikan ekstensi prototipe itu menjadi sama persis dengan jawaban yang paling banyak dipilih, jadi fakta bahwa -6 ini menunjukkan kurangnya pemikiran dari orang-orang yang memilihnya. Dan telah diposting berbulan-bulan sebelum jawaban teratas ... jadi ini terdengar seperti popularitas bukan kontes kode.
user2472643
-3

Jika perlu bertukar elemen pertama dan terakhir saja:

array.unshift( array.pop() );
Alex Moonlight
sumber
Kode ini cacat. Dibutuhkan elemen terakhir dari array kemudian meletakkannya di awal, yang tidak bertukar. Kode ini melakukan ini: [1, 2, 3] => [3, 1, 2]alih-alih [1, 2, 3] => [3, 2, 1].
David Archibald