Javascript takas dizisi öğeleri


228

Bir dizideki iki öğeyi değiştirmenin daha basit bir yolu var mı?

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

Yanıtlar:


412

Sadece bir geçici değişkene ihtiyacınız var.

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

Düzenleme kaçırma 10 yıl sonra bizim kemerleri altında ES6 benimsenmesi bir sürü üst cevap:

Dizi göz önüne alındığında, arr = [1,2,3,4]şimdi bir satırdaki değerleri şu şekilde değiştirebilirsiniz:

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

Bu dizi üretecektir [2,1,3,4]. Bu yıkıcı ödev .


2
ECMAScript 6 Destructuring Assignment kullanmadan bile, mevcut kapsamı geçici bir değişkenle kirletmeden eşzamanlı bir takas gerçekleştirebilir: a = [b, b = a][0];@Jan'ın işaret ettiği gibi Kendimi hala çapraz dil olarak geçici değişken yaklaşımını kullanarak buluyorum (örn. C / C ++ ) ve genellikle aklıma gelen ilk yaklaşım.
Ultimater

3
Diğerlerinin aşağıda gösterildiği gibi es6 ile yerinde (mutasyona uğraması) değiştirebilirsiniz:[ list[y], list[x] ] = [ list[x], list[y] ];
protoEvangelion

[arr[0], arr[1]] = [arr[1], arr[0]]sadece [2, 1]dizinin geri kalanı olmadan üretmek
Yerko Palma

8
@YerkoPalma - ifade [2,1] döndürür, ancak orijinal dizi [2,1,3,4] 'e dönüştürülür
danbars

111

Yerel javascript kullanarak tek bir ifade istiyorsanız, bir ekleme işleminden döndürülen değerin kaldırılan öğeleri içerdiğini unutmayın.

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"

Düzenle:

[0]Olarak ifade sonunda gerekli olan Array.splice()geri dönüş bir dizi ve bu durumda biz geri dizideki tek bir öğe gerektirmez.


3
splice bir dizi döndürür.
Örneğinizde

1
A [x] = A. splice (y, 1, A [x]) [0]; ? mootools'ta Array.implement ({takas: işlev (x, y) {this [y] = this.splice (x, 1, this [y]) [0];}});
ken

Onaylandı, [0] eksik.
Johann Philipp Strathausen

güzel ve kısa, ama @aelgoa dediği gibi, neredeyse yavaş sonra basit takas
ofir_aghai

75

Bu iyi görünüyor ....

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

Howerver kullanma

var b = list[y];

kapsamın geri kalanı için bir b değişkeninin mevcut olacağı anlamına gelir . Bu potansiyel olarak bir bellek sızıntısına yol açabilir. Olası değil, ama yine de kaçınmak daha iyidir.

Belki bunu Array.prototype.swap içine koymak için iyi bir fikir

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

hangi gibi çağrılabilir:

list.swap( x, y )

Bu, hem temiz bir yaklaşımdır kaçınarak bellek sızıntıları ve KURU .


Bunu da beğendim. Array.implement ({takas: işlev (x, y) {x = bu [x]; bu [x] = bu [y]; bu [y] = x; bunu döndür;}});
ken

1
Bu güzel. Belki bazı sınırlar kontrol ediliyor? 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. Sınır kontrolü gereksiz ve gereksizdir. Arayan, istenirse böyle bir kontrol yapmak için gereken her şeye sahiptir, ancak çoğu durumda zaten x ve y'nin sınırlarda olduğunu biliyorsunuz, çünkü bir çeşit döngüdesiniz.
Neil

6
"Potansiyel bellek sızıntısı" nı sadece bir işlev içine sararak önleyemez misiniz?
Şubat'ta Carcigenicate

3
Potansiyel "düzleştirme" biçimindeki yanlışlığı önlemek için, yerleşik türlerin prototip zincirine dokunmam.
AaronDancer

55

Metafilter'daki bazı rastgele kişilere göre , "Javascript'in son sürümleri swapları (diğer şeylerin yanı sıra) çok daha düzgün bir şekilde yapmanıza izin verir:"

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

Hızlı testlerim, bu Pythonic kodunun şu anda "Google Apps Script" (".gs") 'de kullanılan JavaScript sürümünde harika çalıştığını gösterdi . Ne yazık ki, diğer testler bu kodun "Yakalanmayan ReferenceError: Ödevde geçersiz sol taraf" verdiğini gösteriyor. hangi JavaScript sürümünde (".js") Google Chrome Sürüm 24.0.1312.57 m tarafından kullanılır.


2
Bu ES6 teklifinin bir parçasıdır: henüz resmileştirilmemiştir, bu nedenle her yerde çalışacağı varsayılmamalıdır (eğer yapsaydı harika olurdu ...).
Isiah Meadows

2
Mevcut firefox'un en son sürümünde (39.0.3) çalışır.
Jamie

2
Chrome Sürüm 54.0.2840.71 ve önceki Sürümlerde çalışır. Ayrıca, babel gibi bir ES6 transpiler kullanıyorsanız, bu sizin kodunuz olmalıdır .
amoebe

3
Bu çözümü seviyorum. Temiz, amaçlandığı gibi. Çok kötü soru 9 yıl önce soruldu ...
DavidsKanal

2
es6'da standartlaştırılmıştır ve bu özelliğe yıkım denir.
AL-zami

29

Her iki değeri de tamponlamanız gerekmez - sadece bir:

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

13
senin 'tmp' 'b' sonra kullanmak daha makul geliyor
mtasic85

@ofir_aghai evet, haklısın: 10+ yıl önce, bu yanıttan 22 saniye önce başka bir cevap gönderildi (12: 14: 16Z vs 12: 14: 38Z) ...
Marc Gravell

düzenli bir günde, ben onunla sopa. ancak 10 saniyenizin saniye sorunu ve saygısı burada kaldığı için ;-)
ofir_aghai

Üzgünüm oyu değiştirmeme izin vermiyor .. "Bu cevap düzenlenmedikçe
oyunuz

22

Bir dizideki öğeleri şu şekilde değiştirebilirsiniz:

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

Aşağıdaki örneğe bakın:

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

Not: normal değişkenler için aynı şekilde çalışır

var a=1,b=5;
a = [b,b=a][0]

6
Bu ES6 (JavaScript sonraki sürümü) bunu yapmanın standart doğru şekilde çarpıcı biçimde benzer: [list[x], list[y]] = [list[y], list[x]];.
Isiah Meadows

1
Bu yapýlacak hiçbir ţey yok, yapýţtýrma yapýlarak ES6 dizisi takasý. Bu sadece JS iş akışının akıllıca kullanılmasıdır. Satır içi kodlamayı sık kullanırsanız güzel bir takas şekli, örneğinthis[0] > this[1] && (this[0] = [this[1],this[1]=this[0]][0]);
Redu

18

Sayısal değerlerle, bitsel xveya kullanarak geçici bir değişkeni önleyebilirsiniz.

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

veya bir aritmetik toplamı (bunun yalnızca x + y veri türü için maksimum değerden küçükse işe yaradığını belirtmek)

list[x] = list[x] + list[y];
list[y] = list[x] - list[y];
list[x] = list[x] - list[y];

2
Vader'deki gibi dar mı? +1
krosenvold

7
Bir şey yanlış. list[y] = list[x] - list[x];Sadece eşit değil list[y] = 0;mi?
ErikE

3
X veya y, x = y olduğunda da başarısız olur - listeyi [x] sıfıra ayarlar, listenin [x] orijinal değerini korumasını beklediğinizde.
David Cary

1
Teknik olarak, sadece dizinin ilgili alanının dışına taşımadığınız bir geçici değer yaparsınız.
Mark Smit

1
Ne daha basit, ne daha verimli, ne genel.
LoganMzz

17

Bu soru sorulduğunda yoktu, ancak ES2015 dizi yıkımını başlattı ve aşağıdaki gibi yazmanıza izin verdi:

let a = 1, b = 2;
// a: 1, b: 2
[a, b] = [b, a];
// a: 2, b: 1

14
Dizinin içinde böyle değiştirmek için:[list[x], list[y]] = [list[y], list[x]];
Stromata

15

Dizinin ardışık iki öğesini değiştirmek için

array.splice(IndexToSwap,2,array[IndexToSwap+1],array[IndexToSwap]);

13

Http://www.greywyvern.com/?post=265 adresinden özetleyin

var a = 5, b = 9;    
b = (a += b -= a) - b;    
alert([a, b]); // alerts "9, 5"

1
Bunu bir swap(a, b)fonksiyona sararsanız, okunabilirlik konusunda endişelenmenize gerek yoktur.
AccidentalTaylorExpansion

1
Sadece tamsayılar için çalışır
Redu

Bu muhtemelen kötü bir şekilde optimize eder. Bir derleyici bunu bir "takas deyimi" olarak algılayabilir, ancak her iki türün de ints olduğundan ve ayrıca takma ad oluşturmadığından .
mwfearnley


9

Üçüncü değişkeni tanımlamaya gerek kalmadan böyle bir çözümü düşünün:

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

Not: Örneğin dizi uzunluğu için ek kontroller eklemek isteyebilirsiniz. Bu çözüm değiştirilebilir, böylece swapfonksiyonun yeni bir dizi döndürmesi gerekmez, sadece geçirilen dizi üzerinden mutasyon yapar.


Ek olarak, spread operatörü de kullanılabilir:arr.splice(from, 1, arr.splice(to, 1, ...arr[from]))
Orkun Tuzel

7

Aşağıdaki gibi basit bir kimlik işlevini kullanarak, farklı türlerde bile, istediğiniz sayıda nesneyi veya değişmezi değiştirebilirsiniz:

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

Sorununuz için:

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

Bu, JavaScript'te çalışır çünkü bildirilmemesine veya kullanılmamasına rağmen ek argümanları kabul eder. Ödevler a=bvb. İşleve geçtikten sonra olur a.


Hackish ... ama sadece bir kez işlev kullanıyorsanız: daha iyisini yapabilirsiniz list[y] = (function(x){return x})(list[x],list[x]=list[y]);. Eğer ES6 (JS sonraki sürümü) ile ilgilenen bir teklifi ise, bu delicesine kolay: [list[x], list[y]] = [list[y], list[x]. JavaScript'in bir sonraki sürümüne daha işlevsel ve sınıf tabanlı özellikler ekledikleri için çok memnunum.
Isiah Meadows

6

İki veya daha fazla eleman için (sabit sayı)

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

Geçici değişken gerekmez!

Sadece aramayı düşünüyordum list.reverse().
Ama sonra sadece takas olarak çalışacağını fark ettim list.length = x + y + 1.

Değişken eleman sayısı için

Harita ve harita dahil olmak üzere çeşitli modern Javascript yapılarına baktım , ancak ne yazık ki hiçbiri bu eski moda, döngü tabanlı yapıdan daha kompakt veya daha hızlı bir kodla sonuçlandı:

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>


5

Değiştirmenin ilginç bir yolu var:

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

(ES6 yolu)


5
bir dizi için, daha fazlavar 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];

3

İşte mutasyona uğramayan tek bir astar list:

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

(Soru gönderildiğinde 2009'da bulunmayan dil özelliklerini kullanır!)


1

İşte kompakt bir sürüm i1'de i2 ile değeri değiştirir

arr.slice(0,i1).concat(arr[i2],arr.slice(i1+1,i2),arr[i1],arr.slice(i2+1))

Bu, geçici değişken yönteminden daha az verimlidir. Üç kez dilimlenmiş ve üç dilimlenmiş dizi arasında iki nesne ile birleştirilen değiştirilmiş bir diziyi etkili bir şekilde döndürüyorsunuz. Diziye atamak için gereken değeri elde etmek için gerekli olandan iki kattan daha fazla bellek gerekiyordu (bunların hiçbiri yerinde yapılmadı).
Isiah Meadows

1

Dizinin dizinde olup olmadığını ilk olarak kontrol eden bir varyasyon şunlardır:

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

Şu anda thisdizin mevcut değilse geri dönecek , ancak başarısız olduğunda davranışı kolayca değiştirebilirsiniz.


1

Geçici değişken veya ES6 takas yöntemi olmayan bir dizideki ilk ve son öğeyi değiştir [a, b] = [b, a]

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


1

Var olanı mutasyona uğratmak yerine diziyi klonlayan daktilo çözümü

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

0

Sadece eğlenmek için, herhangi bir ekstra değişken kullanmadan başka bir yol olacaktır:

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]


0

Kısacası, yukarıdaki tüm concat ve dilimlemeden biraz daha az çirkin olan çirkin tek katlı versiyon. Kabul edilen cevap gerçekten gitmenin ve okunabilirliğin yoludur.

Verilen:

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

iki endeksin (a ve b) değerlerini değiştirmek isterseniz; o zaman bu yapardı:

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

Örneğin, 3 ve 5'i değiştirmek istiyorsanız, bunu şu şekilde yapabilirsiniz:

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

veya

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

Her ikisi de aynı sonucu verir:

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

#splicehatersarepunks :)


0

ES5'te temp değişkeni kullanmak istemiyorsanız, dizi öğelerini değiştirmenin bir yoludur.

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 ]

Bu şekilde, geçici bir değişken oluşturmak yerine a.splice, kaldırılan öğelerin bulunduğu bir dizi olarak 2 yeni dizi oluşturursunuz . developer.mozilla.org/tr-TR/docs/Web/JavaScript/Reference/…
XCS

Daha iyi yapabilmemizin bir yolu var mı? @Cristy
venkat7668

Kabul edilen cevap basittir. Değişken bildirimi sayısında bir sınırlama olduğunda (çoğunlukla görüşme amacı :)) bu kullanışlı olacaktır. Ama bahsettiğiniz gibi bellek verimli değil. @Cristy
venkat7668

Şahsen bunun kötü bir uygulama olduğunu düşünüyorum ve yeni başlayanlara tavsiye edilmemelidir. Ayrıca okumak çok zor.
XCS

0

bu işlevi deneyin ...

$(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>


0

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


1
Bu kod snippet'i soruyu çözebilir, ancak bir açıklama dahil olmak , yayınınızın kalitesini artırmaya yardımcı olur. Gelecekte okuyucular için soruyu cevapladığınızı ve bu kişilerin kod önerinizin nedenlerini bilmeyebileceğini unutmayın.
Alessio

-1

ES6'yı kullanarak böyle yapmak mümkündür ...

Bu 2 diziye sahip olduğunuzu düşünün ...

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

ve ilk değerleri değiştirmek istersiniz:

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

ve değer:

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

-2
Array.prototype.swap = function(a, b) {
  var temp = this[a];
  this[a] = this[b];
  this[b] = temp;
};

Kullanımı:

var myArray = [0,1,2,3,4...];
myArray.swap(4,1);

1
Kaba olmaya gerek yok. Ayrıca, Arrayprototipi genişletmek istenen şeyin bir parçası değildi - iyi olduğundan daha fazla kafa karıştırıcı olabilir.
Mathias Lykkegaard Lorenzen

Nasıl bazı cevaplar deli olduğunu ifade ve dizi prototip genişletmek olacağını ve bu bir dönüş ekleyerek zincir mümkün hale getirecek ...
user2472643

2
Siz bunu "doğru yol" olarak ifade ediyorsunuz. Yanlış izlenim verebilir. Bunun yerine, tam olarak bana anlattığınız gibi, ne yaptığınızı (prototipi genişleterek) ve bunun nasıl faydalı olduğunu belirtmenizi öneririm.
Mathias Lykkegaard Lorenzen

1
gotcha, üzgünüm benim duruş bazen çift değil ^ _ ^
user2472643

2
Cevap bağlamında bir problemi açıklayan tek kişi sizsiniz ... önce negatif puanlar çalışmayan cevaplar için ayrılmalıdır. İkincisi, bu, çatışmalara neden olmayan zarif bir kullanımla iyi bir cevaptır. Kodu değil teslimatı yargılayın. Ayrıca cevabımda onu çıkardı ve prototip uzantısını hariç tuttuysanız, en çok oylanan cevapla aynı gerçekler haline gelir, bu yüzden -6 olması, oy verenlerin düşünce eksikliğini gösterir. Üst yanıttan aylar önce yayınlandı ... bu yüzden kod yarışması değil popülerlik gibi geliyor.
user2472643

-3

Sadece ilk ve son elemanları takas etmeniz gerekiyorsa:

array.unshift( array.pop() );

Bu kod kusurlu. Dizinin son elemanını alır ve daha sonra onu koyar, bu takas olmaz. Bu kod bunu yapar: [1, 2, 3] => [3, 1, 2]yerine [1, 2, 3] => [3, 2, 1].
David Archibald
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.