Soru Nesne dizisini JavaScript'teki string özellik değerine göre sırala


Bir dizi JavaScript nesnem var:

var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];

Onları değerine göre nasıl sıralayabilirim? last_nom JavaScript’te

biliyorum sort(a,b)Ama bu sadece dizeler ve sayılar üzerinde çalışıyor gibi görünüyor. Nesnelerime bir toString yöntemi eklemem gerekir mi?


1829
2017-07-15 03:17


Menşei


Bu betik, kendi karşılaştırma işlevinizi veya sıralayıcınızı yazmak istemediğiniz sürece bunu yapmanızı sağlar: thomasfrank.se/sorting_things.html - Baversjo


Cevaplar:


Kendi karşılaştırma fonksiyonunuzu yazmak için yeterince kolay:

function compare(a,b) {
  if (a.last_nom < b.last_nom)
    return -1;
  if (a.last_nom > b.last_nom)
    return 1;
  return 0;
}

objs.sort(compare);

Veya satır içi (C / o Marco Demaio):

objs.sort(function(a,b) {return (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0);} ); 

2716
2017-07-15 03:35



Veya satır içi: objs.sort (işlev (a, b) {dönüş (a.last_nom> b.last_nom)? 1: ((b.last_nom> a.last_nom)? -1: 0);}); - Marco Demaio
Resmi dokümanlar: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/... - mikemaccana
return a.last_nom.localeCompare(b.last_nom) da çalışacak. - Cerbrus
alanın sayısal olduğu bir sıralama arayanlar için karşılaştırma işlevi gövdesi: return a.value - b.value; (ASC) - Andre Figueiredo
@Cerbrus localeCompare yabancı dillerdeki aksanlı karakterler kullanıldığında ve daha zarifken önemlidir. - Marcos Lima


Nesneleri geçirdiğiniz değerlere göre sıralayan bir dinamik sıralama işlevi de oluşturabilirsiniz:

function dynamicSort(property) {
    var sortOrder = 1;
    if(property[0] === "-") {
        sortOrder = -1;
        property = property.substr(1);
    }
    return function (a,b) {
        var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
        return result * sortOrder;
    }
}

Yani böyle bir dizi nesneye sahip olabilirsiniz:

var People = [
    {Name: "Name", Surname: "Surname"},
    {Name:"AAA", Surname:"ZZZ"},
    {Name: "Name", Surname: "AAA"}
];

... ve yaptığınız zaman işe yarayacak:

People.sort(dynamicSort("Name"));
People.sort(dynamicSort("Surname"));
People.sort(dynamicSort("-Surname"));

Aslında bu soruya zaten cevap veriyor. Bölümün bir kısmı yazılmıştır, çünkü birçok kişi benimle iletişime geçerek şikayetçi olmuştur. Birden çok parametre ile çalışmıyor.

Çoklu Parametreler

Birden çok sıralama parametresiyle sıralama işlevleri oluşturmak için aşağıdaki işlevi kullanabilirsiniz.

function dynamicSortMultiple() {
    /*
     * save the arguments object as it will be overwritten
     * note that arguments object is an array-like object
     * consisting of the names of the properties to sort by
     */
    var props = arguments;
    return function (obj1, obj2) {
        var i = 0, result = 0, numberOfProperties = props.length;
        /* try getting a different result from 0 (equal)
         * as long as we have extra properties to compare
         */
        while(result === 0 && i < numberOfProperties) {
            result = dynamicSort(props[i])(obj1, obj2);
            i++;
        }
        return result;
    }
}

Böyle bir şey yapabilmenizi sağlayan:

People.sort(dynamicSortMultiple("Name", "-Surname"));

Prototipe Eklemek

(Hemen aşağıda yer alan uygulamadan ilham alınmıştır. Mike R'ler Cevap)

Yerel bir nesne prototipini değiştirmenizi tavsiye etmem ama sadece bir örnek vermek için bunu kendi nesnelerinizde uygulayabilirsiniz (Bunu destekleyen ortamlar için, ayrıca kullanabilirsiniz Object.defineProperty Bir sonraki bölümde gösterildiği gibi, en azından son bölümde açıklandığı gibi, sayılabilir olmanın olumsuz yan etkisine sahip değildir.

Prototip uygulaması aşağıdaki gibi olacaktır (İşte çalışan bir örnek):

//Don't just copy-paste this code. You will break the "for-in" loops
!function() {
    function _dynamicSortMultiple(attr) {
       /* dynamicSortMultiple function body comes here */
    }
    function _dynamicSort(property) {
        /* dynamicSort function body comes here */
    }
    Array.prototype.sortBy = function() {
        return this.sort(_dynamicSortMultiple.apply(null, arguments));
    }
}();

Prototipe Ekleme "Tamam" Yolu

IE v9.0'ı hedefliyorsanız ve daha önce de belirttiğim gibi, Object.defineProperty bunun gibi (çalışma örneği):

//Won't work below IE9, but totally safe otherwise
!function() {
    function _dynamicSortMultiple(attr) {
       /* dynamicSortMultiple function body comes here */
    }
    function _dynamicSort(property) {
        /* dynamicSort function body comes here */
    }
    Object.defineProperty(Array.prototype, "sortBy", {
        enumerable: false,
        writable: true,
        value: function() {
            return this.sort(_dynamicSortMultiple.apply(null, arguments));
        }
    });
}();

Bu kadar kabul edilebilir bir uzlaşma olabilir bağlayıcı operatör geldiğinde.

Tüm bu prototip eğlencesi bunu sağlar:

People.sortBy("Name", "-Surname");

Bunu Okumalısın

Doğrudan prototip erişim yöntemini (Object.defineProperty iyi) kullanırsanız ve diğer kod denetlemez hasOwnProperty, yavru kedi ölür! Tamam, dürüst olmak gerekirse, herhangi bir yavru kedi için hiçbir zarar gelmez ama muhtemelen işler bozulacak ve takımınızdaki diğer geliştiriciler senden nefret edecek:

evil

Son "SortBy" yi görüyor musun? Evet. Hiç hoş değil. Yapabildiğiniz Object.defineProperty'yi kullanın ve Array.prototype'ı tek başına bırakın.


650
2018-01-21 15:03



Lütfen, JavaScript'teki mülk adlarının herhangi bir dize olabileceğini ve "-" ile başlayan mülkleriniz varsa (oldukça düşük olasılıkla ve muhtemelen iyi bir fikir değil), ters sıralama göstergesi olarak başka bir şey kullanmak için dynamicSort işlevini değiştirmeniz gerekir. - Ege Özcan
Ben fark ettim ki dynamicSort() Yukarıdaki örnekte büyük harflerden küçük harfler yerleştirilir. Örneğin, değerlerim varsa APd, Aklin, ve Abe - ASC sıralamadaki sonuçlar Abe, Aklin, APd. Ama örneğinizle, sonuçlar APd, Abe, Aklin. Neyse, bu davranışı düzeltmek için? - Lloyd Banks
@LloydBanks bunu kesinlikle dizeler için kullanıyorsanız, o zaman kullanabilirsiniz var result = a[property].localeCompare(b[property]); yerine var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;. - Ege Özcan
En iyi cevap gibi, undefine özelliklerin mevcut olduğu durumlarda bu başarısız olur: [ { a: 5 }, {a:2}, {}, {a:1} ] - dzh
@ EgeÖzcan Öğeleri en üste veya en alta yerleştirmeli. pastebin.com/g4dt23jU - dzh


underscore.js

alt çizgi kullanın, onun küçük ve harika ...

sortBy_.sortBy (liste, yineleyici, [içerik]) Sıralı bir kopyasını döndürür   liste, her bir değeri çalıştırma sonuçlarına göre artan sırada sıralanır   yineleyici aracılığıyla. Yineleyici de mülkün dize adı olabilir   sıralamak için (örneğin, uzunluk).

var objs = [ 
  { first_nom: 'Lazslo',last_nom: 'Jamf' },
  { first_nom: 'Pig', last_nom: 'Bodine'  },
  { first_nom: 'Pirate', last_nom: 'Prentice' }
];

var sortedObjs = _.sortBy( objs, 'first_nom' );

155
2018-05-10 21:24



David, cevabı söyler misin? var sortedObjs = _.sortBy( objs, 'first_nom' );. objs irade değil Bunun sonucu olarak kendini sınıflandırmak. Fonksiyon olacak dönüş sıralanmış bir dizi. Bu onu daha açık yapar. - Jess
Sıralamayı tersine çevirmek için: var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse(); - Erdal G.
Javascript libary "alt çizgi" yüklemeniz gerekir: <script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"> </script> - and-bri
Ayrıca mevcut Lodash bunu tercih edenler için - WoJ


İnsanların neden bu kadar karmaşık hale geldiğini anlamayın:

objs.sort(function(a, b){
  return a.last_nom > b.last_nom;
});

Daha sıkı motorlar için:

objs.sort(function(a, b){
  return a.last_nom == b.last_nom ? 0 : +(a.last_nom > b.last_nom) || -1;
});

Operatörü ters alfabetik sıraya göre sıralayacak şekilde değiştirin.


141
2018-01-24 19:35



Bu, sıralamada kullanılan işlev -1, 0 veya 1 döndürmesi gerektiği için doğru değildir, ancak yukarıdaki işlev bir boole döndürür. Sıralama, kromda iyi çalışır ancak PhantomJS'de başarısız olur. Görmek code.google.com/p/phantomjs/issues/detail?id=1090 - schup
Bazı motorlar aptallıktan sorumlular, bu şekilde böyle bir istismardı. Cevabımı uygun bir sürümle güncelledim. - p3lim
İlk sürümü çıkarmak için düzenlemeyi öneririm. Daha özlü bu yüzden daha çekici görünüyor, ama en azından güvenilir değil, işe yaramıyor. Birisi bir tarayıcıda çalışırsa ve çalışırsa, bir sorun yaşadıklarını bile fark etmeyebilirler (özellikle yorumları okumamışlarsa). İkinci versiyon düzgün çalışıyor, bu yüzden ilkine gerçekten gerek yok. - Kate
Birden çok parametreli ilk bir sürümü var mı - özellikle saymaya göre alfabetik olarak sıralama - Lion789
@Simon İlk olarak "biraz yanlış" sürümüne sahip olduğum için minnettarım, çünkü daha sıkı uygulama, ayrıştırmak ve anlamak için birkaç saniye sürüyor ve onsuz çok daha zor olurdu. - Aaron Sherman


ES6 / ES2015 veya daha sonra şu şekilde yapabilirsiniz:

objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom));

138
2018-01-29 19:44



Bu, JS 1.1'den beri mevcut, bu yağ ok parçası, ES6 / 2015 parçası. Ama bence hala çok yararlı ve en iyi cevap - Jon Harding
@PratikKelwalkar: Eğer tersine ihtiyacınız varsa, sadece a ve b karşılaştırmalarını değiştirin: objs.sort ((a, b) => b.last_nom.localeCompare (a.last_nom)); - Vlad Bezden
sıralama için alanı ele almak için bir indeks kullanmak da mümkündür: last_nom dizideki sadece sayıyı kullanın: 1 ? - and-bri
@VladBezden cevabınız için teşekkürler! Bu çözüm, çok küçük programlı çaba ve doğru sıralama sonuçları ile bir dizi dizisi olan ilk örnektir: ["Name1", "Name10", "Name2", "başka bir şey", "Name11"]. Doğru şekilde çalışmak için sıralama var objs.sort((a, b) => a.last_nom.localeCompare(b.last_nom, undefined, {numberic: true})); - scipper


Eğer soyadlarını çoğaltmış iseniz, bunları ilk isimle sıralayabilirsiniz.

obj.sort(function(a,b){
  if(a.last_nom< b.last_nom) return -1;
  if(a.last_nom >b.last_nom) return 1;
  if(a.first_nom< b.first_nom) return -1;
  if(a.first_nom >b.first_nom) return 1;
  return 0;
});

51
2017-07-15 04:03



o a< b  a >b biçimlendirme ilginç. - Dodekeract


Prototip mirasını kullanarak bu soruna basit ve hızlı çözüm:

Array.prototype.sortBy = function(p) {
  return this.slice(0).sort(function(a,b) {
    return (a[p] > b[p]) ? 1 : (a[p] < b[p]) ? -1 : 0;
  });
}

Örnek / Kullanım

objs = [{age:44,name:'vinay'},{age:24,name:'deepak'},{age:74,name:'suresh'}];

objs.sortBy('age');
// Returns
// [{"age":24,"name":"deepak"},{"age":44,"name":"vinay"},{"age":74,"name":"suresh"}]

objs.sortBy('name');
// Returns
// [{"age":24,"name":"deepak"},{"age":74,"name":"suresh"},{"age":44,"name":"vinay"}]

Güncelleştirme: Artık orijinal diziyi değiştirmez.


38
2017-07-10 11:54



Sadece başka bir dizi döndürmez. ama aslında orijinal olanı sıralar! - Vinay Aggarwal
Sayıları ile doğal bir sıralama kullandığınızdan emin olmak istiyorsanız (yani, 0,1,2,10,11 vb ...) Radix seti ile parseInt kullanın. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... yani: (parseInt (a [p], 10)> parseInt (b [p], 10))? 1: (parseInt (a [p], 10) <parseInt (b [p], 10))? -1: 0; - Paul
@codehuntr Düzeltdiğiniz için teşekkürler. ama sanırım bu hassaslaştırmayı yapmak için sıralama işlevi yapmak yerine, veri tiplerini düzeltmek için ayrı bir işlev yaparsak daha iyi olur. Sıralama işlevi, hangi özelliğin hangi tür verileri içerdiğini söyleyemediği için. :) - Vinay Aggarwal
Çok hoş. Asc / desc efekti elde etmek için okları ters çevirin. - Abdul Sadik Yalcin


Özel bir karşılaştırma işlevi kullanmak yerine, özel bir nesne türü de oluşturabilirsiniz. toString() yöntem (varsayılan karşılaştırma işlevi tarafından çağrılan):

function Person(firstName, lastName) {
    this.firtName = firstName;
    this.lastName = lastName;
}

Person.prototype.toString = function() {
    return this.lastName + ', ' + this.firstName;
}

var persons = [ new Person('Lazslo', 'Jamf'), ...]
persons.sort();

24
2017-07-15 07:21





Burada çok iyi cevaplar var, ama çok daha karmaşık bir sıralama elde etmek için çok genişletilebileceklerini belirtmek isterim. Yapmanız gereken tek şey OR operatörünü aşağıdaki gibi karşılaştırma işlevlerini kullanmaktır:

objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )

Nerede fn1, fn2... [-1,0,1] döndüren sıralama işlevleri. Bu, "fn1 ile sıralama", "fn2 ile sıralama" ve SQL'de SİPARİŞ'e neredeyse eşittir.

Bu çözüm, davranışlarına dayanmaktadır || değerlendiren operatör İlk değerlendirilen ifade doğruya dönüştürülebilir.

En basit formu bunun gibi tek satırlı bir işlevi vardır:

// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )

İle iki adımı olması last_nom,first_nom Sıralama düzeni şöyle görünecekti:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) || 
                  a.first_nom.localeCompare(b.first_nom)  )

Genel bir karşılaştırma işlevi böyle bir şey olabilir:

// ORDER BY <n>
let cmp = (a,b,n)=>a[n].localeCompare(b[n])

Bu işlev, sayısal alanları, büyük / küçük harf duyarlılığını, aritmetik veri türlerini vb. Desteklemek için genişletilebilir.

Onları sıralama önceliğine göre zincirleme ile kullanabilirsiniz.

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> cmp(a,b, "last_nom") || cmp(a,b, "first_nom") )
// ORDER_BY last_nom, first_nom DESC
objs.sort((a,b)=> cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
// ORDER_BY last_nom DESC, first_nom DESC
objs.sort((a,b)=> -cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )

Buradaki nokta, işlevsel yaklaşımı olan salt JavaScript'in, harici kütüphaneler veya karmaşık kodlar olmadan uzun bir yol alabilmesidir. Ayrıca, hiçbir ayrıştırma yapılması gerekmediğinden çok etkilidir.


14
2018-05-05 11:36