2010-09-16 5 views
26

varsayalım öylesine gibi, bir JavaScript dizisi var: Ben diziyi sıralamak istediğinizJavaScript: orijinal unsurları bakımından sıralanmış elemanların konumunu gösterir diziyi sıralar ve indicies dizisi dönmek

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

. Açıkçası, ben sadece dizi sıralamak yapabilirsiniz:

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

Ama benim gerçekten istediğiniz orijinal unsurları bakımından sıralanmış elemanların konumunu gösterir endeksleri bir dizidir. 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öntem adı ise sortIndices(), o zaman ister ne olduğu:, 'b', 0 ° C'de

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

'bir 3' konumundaki olduğu

olduğu, 'c' 1 de ve 'd' orijinal dizide 2 idi. Böylece, [3, 0, 1, 2].

Bir çözüm dizinin bir kopyasını sıralamak ve sonra sıralanmış diziyi dolaşmak ve her dizinin orijinal dizisindeki 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?

cevap

29
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üzenleme

Siz doğru yaklaşık for .. in bulunmaktadır. 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. Eğer Dizi prototip fonksiyonları ekleme ve diziler inline mutasyona hakkında hissediyorum, ama bu karşılaştırılabilir herhangi nesnelerin bir dizinin sıralama nasıl sağladığı konusuna

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(",")); 
+4

+1 Ancak bence bir dizi için in 'in' loop kullanmamalısınız. – Tomalak

+0

Bu iyi bir fikir. Bunu deneyeceğim. (Çalıştığımda bunu kabul edeceğim.) – Jeremy

+0

@Tomalak: Sizinle ilgili olarak size katılıyorum .. İçeride çok fazla sorunla karşılaştım. – Jeremy

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

YMMV. Array.prototype.sort gibi, sıralama için kullanılabilecek isteğe bağlı bir işlev alır.

bir örneği,

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] 
+0

Neden .apply' yerine '.call' kullanılmıyor? – strager

+0

çü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 her seferinde bir dizi oluşturulmasına gerek yoktur. Şimdi güncellenir –

17

Sadece sayılar 0..n-1 içeren bir dizi doldurun ve bir karşılaştırma fonksiyonu ile o sıralamak istiyorum.

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

Bu harika, ve eğer değerler eşitse, endeksleri (a ve b) karşılaştırarak biraz daha iyi olabilir (sıralamayı stabil hale getirin!). I.e, değiştir ... ... test [a]> test [b]? 1: 0 'yerine ... test [a]> test [b]? 1: a

2

Dave Aaron Smith doğru (yorum yapamıyorum), ancak Array map() işlevini kullanmanın ilginç olduğunu düşünüyorum.

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

için ES6 (a 0->N-1 göstergesi kümesinin oluşturulması ve giriş değerlerine dayanarak bu sıralama) kullanılarak tek bir çizgi ile yapabilirsiniz.

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)