Dizi öğesini bir dizi konumundan diğerine taşıma


522

Bir dizi eleman taşımak için nasıl anlamaya zor yaşıyorum. Örneğin, aşağıdakiler göz önüne alındığında:

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

Daha 'd'önce taşınacak bir işlevi nasıl yazabilirim 'b'?

Veya 'a'sonra 'c'mı?

Hareketten sonra, diğer öğelerin endeksleri güncellenmelidir. Bu, ilk örnekte arr [0] hareketinden sonra = 'a', arr [1] = 'd' arr [2] = 'b', arr [3] = 'c', arr [4] = 'e'

Bu oldukça basit olmalı, ama başımı etrafına satamıyorum.


3
iyi bu soru eski ama altın
Jalal

ES6const changeValuePosition = (arr, init, target) => {[arr[init],arr[target]] = [arr[target],arr[init]]; return arr}
muhsalaa

Sadece takasları unsur O initve target.
Matt F.

Yanıtlar:


671

Npm'de bir sürüm istiyorsanız, array-move bu uygulamaya en yakın olanıdır, ancak aynı uygulama değildir. Daha fazla ayrıntı için kullanım bölümüne bakın. Bu cevabın önceki sürümü (değiştirilmiş Array.prototype.move) npm'de array.prototype.move adresinde bulunabilir .


Bu işlevle oldukça iyi bir başarı elde ettim:

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

Sonuncunun returnsadece test amaçlı olduğunu unutmayın: splicedizideki işlemleri yerinde gerçekleştirir, bu nedenle bir dönüş gerekli değildir. Ek olarak, bu moveyerinde bir işlemdir. Bundan kaçınmak ve bir kopyasını iade etmek istiyorsanız, düğmesini kullanın slice.

Kod boyunca adım atma:

  1. Eğer new_indexdizinin uzunluğundan daha büyük olduğu için, yeni düzgün yastığa dizi (sanırım) istiyorum undefineds. Bu küçük pasaj undefined, uygun uzunluğa sahip olana kadar diziyi iterek bunu halleder .
  2. Sonra, arr.splice(old_index, 1)[0]eski elementi ekliyoruz. spliceeklenmiş öğeyi döndürür, ancak bir dizide bulunur. Yukarıdaki örneğimizde bu buydu [1]. Bu yüzden o dizinin ilk dizinini alıp ham olanı elde ediyoruz 1.
  3. Sonra splicebu öğeyi new_index'in yerine eklemek için kullanırız. Yukarıdaki diziyi eğer doldurduğumuzdan, new_index > arr.lengthnegatif bir sayı geçmek gibi garip bir şey yapmadıysa, muhtemelen doğru yerde görünecektir.

Negatif endeksleri açıklamak için daha ince bir versiyon:

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

Hangi gibi array_move([1, 2, 3], -1, -2)düzgün bir şekilde açıklamalı (son elemanı ikinci yerine son yerine taşı). Bunun sonucu olmalı [1, 3, 2].

Her iki durumda da orijinal söz konusu, sen yapardın array_move(arr, 0, 2)için asonrasÖ c. İçin dönce b, sen yapardın array_move(arr, 3, 1).


19
Mükemmel çalışıyor! Ve açıklaman çok açık. Bunu yazmaya zaman ayırdığınız için teşekkürler.
Mark Brown

16
Nesne ve Dizi prototiplerini değiştirmemelisiniz, öğeleri yinelerken sorunlara neden olur.
burak emre

9
@burakemre: Bence sonuca o kadar açık bir şekilde ulaşılamıyor. En iyi JS programcıları (ve en popüler kütüphaneler) .hasOwnPropertyfor..in gibi şeylerle, özellikle de prototipleri değiştiren Prototype ve MooTools gibi kütüphanelerle tekrarlarken bir kontrol kullanır. Her neyse, bunun gibi nispeten sınırlı bir örnekte özellikle önemli bir sorun olduğunu hissetmedim ve toplulukta prototip modifikasyonunun iyi bir fikir olup olmadığı konusunda güzel bir bölünme var. Normal olarak, yineleme sorunları en az endişe kaynağıdır.
Reid

3
1. adımdaki döngüye gerek yoktur, sadece blok this[new_index] = undefined;içinde kullanabilirsiniz if. Javascript dizileri seyrek olduğundan, dizi boyutunu .spliceçalışmak için new_index içerecek şekilde, ancak araya giren elemanlar oluşturmaya gerek kalmadan genişletecektir .
Michael

3
@Michael: İyi bir nokta - ama yapmak this[new_index] = undefinedaslında doğru dizinden önceundefined dizi yuvasına koyacaktır . (Örneğin, olacak yuvaya 10 ve seyrekliği yolunda olup olmadığını biz yapabiliriz, Rather'ın 9. yuvasına) diğer ek yeri çağrısı olmadan (bir if / else yerine olun). [1,2,3].move(0,10)1undefinedthis[new_index] = this.splice(old_index, 1)[0]
Reid

268

İşte JSPerf'te bulduğum bir astar ...

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

hangi okumak harika, ama performans (küçük veri kümelerinde) istiyorsanız deneyin ...

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

Kredi alamıyorum, hepsi Richard Scarrott'a gitmeli . Bu performans testinde daha küçük veri kümeleri için ek yeri tabanlı yöntemi yener . Bununla birlikte , Darwayne'nin işaret ettiği gibi daha büyük veri setlerinde önemli ölçüde yavaştır .


2
Daha performanslı çözümünüz büyük veri kümelerinde daha yavaştır. jsperf.com/array-prototype-move/8
Darwayne

44
Bu gerçekten aptalca bir geleneğe benziyor. Küçük veri kümelerindeki performans önemsiz bir kazançtır, ancak büyük veri kümelerindeki kayıp önemli bir kayıptır. Net borsa negatif.
Kyeotic

3
@Reid Bu bir gereklilik değildi. IMO, dizi uzunluğunun değiştirilmediğini varsaymak uygundur.
robsch

3
Bir hat çözümü iki durumu ele from >= to ? this.splice(to, 0, this.splice(from, 1)[0]) : this.splice(to - 1, 0, this.splice(from, 1)[0]);
Rob L

13
Lütfen yerleşik prototipleri asla değiştirmeyin. nczonline.net/blog/2010/03/02/…
LJHarb

230

Bu yolu seviyorum. Kısa ve işe yarıyor.

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

Not: Her zaman dizi sınırlarınızı kontrol etmeyi unutmayın.

Snippet'i jsFiddle'da çalıştırın


29
Array.splice, kaldırılan değerleri yeni bir Array içinde döndürdüğünden, bunu bir astar olarak yazabilirsiniz ... arr.splice (index + 1, 0, arr.splice (index, 1) [0]);
Eric

49
Şahsen ben 3 satır kodunu tercih ederim. Anlamak daha kolay: Öğenin bir kopyasını alın; diziden kaldır; yeni bir konuma takın. Tek astar daha kısa ama diğer insanların anlaması çok açık değil ...
Philipp

2
Kısa ve basit kod. Ama 2019 !!, Dizinin bir klonunu oluşturun ve diziyi mutasyona uğratmak yerine onu döndürün. Bu, işlevinizin "arraymove" işlevini işlevsel programlama standartlarına uygun hale getirir
SamwellTarly

4
Tamam ama her şey ne olduğunu ne de olmak zorunda fonksiyonel programlama uyumlu; ayrıca bu, yerel dizileri manipüle etmek için bir prosedür içindeki fonksiyonel programlamada da yararlı olabilir.
SteakOverflow

36

Splice () yöntemi, bir diziye / diziden öğe ekler / kaldırır ve kaldırılan öğeleri döndürür .

Not: Bu yöntem orijinal diziyi değiştirir. / 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"]

işlev zincirlenebilir olduğu için bu da çalışır:

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

burada demo


Bunu kullanan herhangi bir kütüphane var mı? Oldukça temiz!
uicoded

Bununla ilgili diğer yorumları görün: Dizi ve Nesne gibi yerleşik prototipleri değiştirmek kötü bir fikirdir. Bir şeyleri kıracaksın.
jeoidesik

27

Benim 2c. Okuması kolay, çalışıyor, hızlı, yeni diziler yaratmıyor.

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

2
İlk işlev dizesinde arraysonunda olduğu gibi dönmelisiniz.
Sergey Voronezhskiy

3
Doğru bunu nasıl özledim? Sabit!
Merc

En basit ve esnek çözümünüzü seviyorum. Teşekkür!
Roman M.Koss

18

Dizi boyutunu sabit tutmak için taşınması gereken öğenin yerine bir şey itme @Reid'den bu fikri aldım. Bu hesaplamaları kolaylaştırır. Ayrıca, boş bir nesneyi itmek, daha sonra benzersiz bir şekilde arama yapabilmenin ek avantajlarına sahiptir. Bu çalışır çünkü iki nesne aynı nesneye gönderme yapana kadar eşit değildir.

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

İşte kaynak diziyi ve kaynak, hedef dizinlerini alan işlev. Gerekirse Array.prototype öğesine ekleyebilirsiniz.

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

1
Bu umut verici görünüyor ... ve javascript js karşılaştırmaları hakkında bilmiyordum. Teşekkürler!
Mark Brown

Dava için çalışmıyor sourceIndex = 0,destIndex = 1
Sergey Voronezhskiy

destIndexkaynak öğenin diziye taşınmasından önceki dizin olması anlamına gelir.
Anurag

Bu şimdiye kadarki en iyi cevap. Diğer cevaplar benim takımımda birkaç birim testinde başarısız oldu (nesneyi ileriye doğru hareket
Ilya Ivanov

16

Bu @ Reid'in çözümüne dayanmaktadır. Dışında:

  • ArrayPrototipi değiştirmiyorum .
  • Bir öğeyi sınırların dışına taşımak undefinedöğeleri oluşturmaz , sadece öğeyi en sağa taşır.

İşlev:

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

Birim testleri:

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

bu yanlıştır, eğer bir gönderi konumu eklerseniz, öğeyi kaldırdığınızdan dolayı dizin değişecektir
Yao Zhao

Teşekkür ederim. Ben boş bir öğe (indexARemove kullanırken) oluşan bir null öğeyi terk etmeden bir öğeden kaldırmak istedim. Dizinin sonuna kaldırmak istediğiniz öğeyi taşımak için yönteminizi kullandım ve sonra pop () kullanılır yöntem kaldırmak için.
Luke Schoen

benim durumum için yararlı, "öğeyi en doğru konuma taşımak" özelliğini sevdim. thx
bFunc

11

İşte isteğe bağlı bir parametreye sahip tek astarlı ES6 çözümümon .

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

Tarafından önerilen ilk çözümün uyarlanması digiguru

Parametre on, fromtaşımak istediğiniz öğeden başlayan eleman sayısıdır .


Çözüm gayet iyi. Ancak, bir prototipi genişlettiğinizde ok işlevini kullanmamalısınız, çünkü bu durumda 'this' bir dizi örneği değil, örneğin Window nesnesi.
wawka

7

Bir yaklaşım, dilim yöntemini kullanarak parçaları istediğiniz sırayla yeni bir dizi oluşturmak olacaktır.

Misal

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) size ['a'] verir
  • arr.slice (2,4) size ['b', 'c'] verir
  • arr.slice (4) size ['e'] verir

1
arr2Birleştirme işlemleri nedeniyle sonuçlarınızın bir dize olduğunu anlıyorsunuz , değil mi? :) Sonunda oluyor "adc,de".
Ken Franqueiro

6

Yardımcı olabilir spliceyöntemi Array: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice

Diziyi aktif olarak yeniden endekslemek zorunda olduğu için nispeten pahalı olabileceğini unutmayın.


Evet, ancak eki gerçekleştirir etmez dizi dizileri güncellenir, bu da yeni çıkardığım öğeyi nereye yerleştireceğimi bulmamı zorlaştırır. Özellikle her iki yönde de hareketleri yapabilmek için işleve ihtiyacım olduğu için
Mark Brown

@ Mark: dizeyi birleştirmeyin ve aynı değişkene kaydetmeyin, yeni bir dizgi yapın ve bunu birleştirin. Cevabımı aşağıda görebilirsiniz.
Jared Updike

6

Bazı temel hesabı uygulayabilir ve dizi öğesini bir konumdan diğerine taşımak için evrensel bir işlev oluşturabilirsiniz.

JavaScript için şöyle görünür:

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; 

}

Ayrıntılı açıklama için "gloommatter" daki "hareketli dizi elemanlarına" göz atın.

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


1
Bu, yeni diziler ayırmadığı için doğru cevap olmalıdır. Teşekkürler!
Cᴏʀʏ

Bağlantı koptu.
Rokit

6

Buradaki cevaba ECMAScript 6dayanarak değişmez bir çözüm uyguladım @Merc:

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

Değişken adları kısaltılabilir, sadece uzun olanlar kullanılabilir, böylece kod kendini açıklayabilir.


kesinlikle daha iyi bir cevap, mutasyonlar yan etkiler yaratır
Matt Lo

1
Sadece meraktan, neden sadece dönmek arrayderhal fromIndex === toIndexve sadece oluşturmak newArrayo durumda değilse? Değiştirilemezlik, değişiklik yapılmasa bile her işlev çağrısı için bir yeni kopyanın oluşturulması gerektiği anlamına gelmez. Sadece b / c'den bu işlevin artan uzunluğunu (ekleme tabanlı tek gömleklere göre) istemek performanstır ve kullanıma bağlı olarak fromIndexçoğu zaman eşit olabilir toIndex.
Robert Monfera

5

Ben değişmez bir hareket yöntemi gerekli (bir orijinal dizi değişmedi), bu yüzden @ Reid's kabul cevap sadece eki yapmadan önce dizinin bir kopyasını oluşturmak için Object.assign kullanmak için adapte.

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

İşte bunu gösteren bir jsfiddle .


İnsanların mutasyonları dikkate aldığını görmek her zaman iyidir.
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


2

Hem küçük hem de büyük mesafeleri hareket ettirirken bunlardan ikisini biraz daha iyi çalışmak için birleştirdim. Oldukça tutarlı sonuçlar alıyorum, ancak bu muhtemelen farklı boyutlarda, vb.İçin farklı çalışmak için benden daha akıllı biri tarafından biraz değiştirilebilir.

Nesneleri hareket ettirirken diğer yöntemlerden bazılarını kullanmak, küçük mesafeler ek yeri kullanmaktan önemli ölçüde daha hızlıdır (x10). Bu, dizi uzunluklarına bağlı olarak değişebilir, ancak büyük diziler için geçerlidir.

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


2

Array prototipi ile oynamak birçok yerde ( Array.prototype'e özel işlevler ekleyerek ) kötü bir fikir olabilir, yine de çeşitli gönderilerden en iyilerini birleştirdim, modern Javascript kullanarak bununla geldim:

    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

Umut herkes için yararlı olabilir


2

Bu sürüm tüm amaçlar için ideal değildir ve herkes virgül ifadelerini sevmez, ancak işte saf bir ifade olan ve yeni bir kopya oluşturan tek astar:

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

Performansı biraz iyileştirilmiş bir sürüm, herhangi bir hareket gerekmiyorsa giriş dizisini döndürür, dizi değişmeyeceğinden, değişmez kullanım için hala sorun olmaz ve hala saf bir ifadedir:

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

İkisinden birinin çağrısı

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

yani yeni bir kopya oluşturmak için yayılmaya dayanır. Sabit bir aritite 3 kullanılması move, ya tek ekspresyon özelliğini ya da tahribatsız doğayı ya da performans faydasını tehlikeye atacaktır splice. Yine, üretim kullanımı için bir öneri yerine bazı kriterleri karşılayan bir örnektir.


1

Array.move.js

özet

Bir dizi içindeki öğeleri taşır, taşınan öğeleri içeren bir dizi döndürür.

Sözdizimi

array.move(index, howMany, toIndex);

Parametreler

index : Öğelerin taşınacağı dizin . Negatifse, dizin sondan başlayacaktır.

howmany : Öğe sayısı taşınmaya indeksi .

toIndex : Taşınan öğelerin yerleştirileceği dizinin dizini. Negatifse , toIndex en baştan başlar.

kullanım

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

2
.moveÇalışması gerektiği gibi görünüyor olsa da (test etmedim), herhangi bir standardın parçası olmadığını unutmayın. Çoklu doldurma / maymun karması işlevlerinin sayılabilecek her şeyin kendilerine ait olduğunu varsayan bazı kodları kırabileceği konusunda insanları uyarmak da iyidir.
Jeremy J Starcher

1
a = ["a", "b", "c"]; a. hareket (0,1,1); // a = ["a", "b", "c"], ["b", "a", "c"] olmalıdır
Leonard Pauli

2
Bu özellik kullanılmıyor ve artık desteklenmeyebilir. Dikkatli olun Bakınız: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Mostafa

1

@Reid'in güzel cevabını kullandım , ancak bir elemanın bir dizinin sonundan bir adım daha ileriye taşınmasıyla mücadele ettim (bir döngüdeki gibi ). Örneğin, ['a', 'b', 'c'] .move (2,3) öğesini çağırarak ['c', 'a', 'b'] olmalıdır.

Bunu new_index> = this.length için durumu değiştirerek başardım.

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

1

Reid'in mükemmel cevabına ek olarak (ve yorum yapamayacağım için); Hem negatif indeksleri hem de çok büyük indeksleri "devrilme" yapmak için modulo kullanabilirsiniz:

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


Evet - negatif endeksler desteklendiğinden, bana göre tanımsız değerler eklemek yerine çok büyük endeksleri sarmak mantıklı görünüyor.
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)


1

Bunun bir takas sorunu olduğunu düşündüm ama öyle değil. İşte benim tek katmanlı çözümüm:

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

İşte küçük bir test:

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

Soru, öğeleri değiştirmekle ilgili değildi. Yazar bir ekleme stratejisi için bir çözüm istedi.
Andreas Dolk

Eldeki soru ile ilgili olarak, bu objektif olarak yanlış cevaptır.
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 );

sonuç:

["b", "a", "c", "d"]

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


1
SO hoş geldiniz! 21 ek cevap var ... bu yüzden, lütfen sadece kod koymayın. Cevabınızın faydasını açıklayın.
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);


0

Dizi kopyası olmayan bağlanabilir sürüm:

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

0

Bence en iyi yol Diziler için yeni bir mülk tanımlamak

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]

0

Mutasyon olmadan ES6 dizi yayma operatörü kullanan bir başka saf JS varyantı

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


0

Bu yöntem orijinal diziyi koruyacak ve sınırlayıcı hataları kontrol edecektir.

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