Soru Javascript: Diziyi sıralayın ve sıralı öğelerin orijinal öğelere göre konumunu gösteren bir dizi uyarı döndürün


Bir Javascript dizilimin olduğunu varsayalım:

var test = ['b', 'c', 'd', 'a'];

Diziyi sıralamak istiyorum. Açıkçası, diziyi sıralamak için bunu yapabilirim:

test.sort(); //Now test is ['a', 'b', 'c', 'd']

Ama gerçekten istediğim, sıralı öğelerin orijinal öğelere göre konumunu gösteren bir dizi dizin. Bunu nasıl ifade edeceğimi tam olarak bilmiyorum, belki de bu yüzden nasıl yapılacağını bulmakta zorlanıyorum.

Böyle bir yönteme sortIndices () denirse, o zaman ne isterim:

var indices = test.sortIndices();
//At this point, I want indices to be [3, 0, 1, 2].

'a', 3 konumundaydı, 'b', 0'daydı, 'c', 1'deydi ve 'd', orijinal dizide bir 2 idi. Böylece, [3, 0, 1, 2].

Bir çözüm, dizinin bir kopyasını sıralamak ve sıralanan dizide dolaşmak ve orijinal dizideki her öğenin konumunu bulmak olacaktır. Ama bu rahatsız edici hissettiriyor.

İstediğimi yapan mevcut bir yöntem var mı? Eğer değilse, bunu yapan bir yöntem yazmaktan nasıl vazgeçersiniz?


28
2017-09-16 20:27


Menşei




Cevaplar:


var test = ['b', 'c', 'd', 'a'];
var test_with_index = [];
for (var i in test) {
    test_with_index.push([test[i], i]);
}
test_with_index.sort(function(left, right) {
  return left[0] < right[0] ? -1 : 1;
});
var indexes = [];
test = [];
for (var j in test_with_index) {
    test.push(test_with_index[j][0]);
    indexes.push(test_with_index[j][1]);
}

Düzenle

Sizler haklısınız for .. in. Sık sık sinir bozucu bir şekilde gözlemlediğim dizi prototipini mısralıyorsa bu kırılacak. İşte bu, sabit ve daha kullanışlı bir işleve sarılmış ile.

function sortWithIndeces(toSort) {
  for (var i = 0; i < toSort.length; i++) {
    toSort[i] = [toSort[i], i];
  }
  toSort.sort(function(left, right) {
    return left[0] < right[0] ? -1 : 1;
  });
  toSort.sortIndices = [];
  for (var j = 0; j < toSort.length; j++) {
    toSort.sortIndices.push(toSort[j][1]);
    toSort[j] = toSort[j][0];
  }
  return toSort;
}

var test = ['b', 'c', 'd', 'a'];
sortWithIndeces(test);
alert(test.sortIndices.join(","));

33
2017-09-16 20:37



+1 ama sanırım bir daha kullanamazsın for .. in bir dizi üzerinde döngü. - Tomalak
Bu iyi bir fikir. Bunu deneyeceğim. (Çalıştığımda kabul edeceğim.) - Jeremy
@Tomalak: Seninle ilgili olarak sana katılıyorum .. İçeride çok fazla sorunla karşılaştım. - Jeremy
kullanma for-in bir Array ile neredeyse her zaman çok kötü bir fikirdir. - strager
StackSort'ta çalışıyor! gkoberger.github.io/stacksort - EMBLEM


Ben sadece 0..n-1 sayıları olan bir diziyi doldurur ve bunu bir karşılaştırma işleviyle sıralardım.

var test = ['b', 'c', 'd', 'a'];
var len = test.length;
var indices = new Array(len);
for (var i = 0; i < len; ++i) indices[i] = i;
indices.sort(function (a, b) { return test[a] < test[b] ? -1 : test[a] > test[b] ? 1 : 0; });
console.log(indices);

19
2018-01-21 13:13



Bu harikadır ve eğer değerler eşitse, indeksleri (a ve b) karşılaştırarak biraz daha iyi olabilir (sıralamayı stabil hale getirin!). I.e, değiş ... test[a] > test[b] ? 1 : 0 için ... test[a] > test[b] ? 1 : a < b ? -1 : 1, başı olarak: stackoverflow.com/questions/1427608/... - David Baird


Dave Aaron Smith doğrudur (yorum yapamıyorum), ancak Array haritasını () burada kullanmak ilginç.

var test = ['b', 'c', 'd', 'a'];
// make list with indices and values
indexedTest = test.map(function(e,i){return {ind: i, val: e}});
// sort index/value couples, based on values
indexedTest.sort(function(x, y){return x.val > y.val ? 1 : x.val == y.val ? 0 : -1});
// make list keeping only indices
indices = indexedTest.map(function(e){return e.ind});

3
2017-12-15 23:35





Array.prototype.sortIndices = function (func) {
    var i = j = this.length,
        that = this;

    while (i--) {
        this[i] = { k: i, v: this[i] };
    }

    this.sort(function (a, b) {
        return func ? func.call(that, a.v, b.v) : 
                      a.v < b.v ? -1 : a.v > b.v ? 1 : 0;
    });

    while (j--) {
        this[j] = this[j].k;
    }
}

Array prototipine ve mutasyona uğrayan dizilere satır içi ekleme hakkında ne hissettiğinizi anlatan YMMV, ancak bu, karşılaştırılabilecek herhangi bir nesnenin bir dizisinin sıralanmasına izin verir. Sıralamak için kullanılabilecek isteğe bağlı bir işlev alır. Array.prototype.sort.

Bir örnek,

var test = [{b:2},{b:3},{b:4},{b:1}];

test.sortIndices(function(a,b) { return a.b - b.b; });

console.log(test); // returns [3,0,1,2]

2
2017-09-16 23:01



Neden kullanılmaz .call yerine .apply? - strager
çünkü daha sonra alfabede :) dürüst olmak için gerçek bir neden yok, muhtemelen bu durumda çağrı kullanmak için daha mantıklı, o zaman bir dizi her zaman oluşturulmasına gerek yoktur. Şimdi güncellenecek - Russ Cam


Bunu, es6'yı kullanarak tek bir satır ile gerçekleştirebilirsiniz. 0->N-1 dizin dizisi ve giriş değerlerine göre sıralama).

var test = ['b', 'c', 'd', 'a']

var result = Array.from(Array(test.length).keys())
                  .sort((a, b) => test[a] < test[b] ? -1 : (test[b] < test[a]) | 0)

1
2018-02-13 02:20