Nesne dizisini dize özellik değerine göre sırala


2763

Bir dizi JavaScript nesnesi var:

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

Bunları last_nomJavaScript'teki değerine göre nasıl sıralayabilirim ?

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


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

en hızlı yol, hem tarayıcıda hem de düğümde yerel olarak çalışan, her türlü girişi, hesaplanan alanları ve özel sıralama düzenlerini destekleyen izomorfik sıralama dizisi modülünü kullanmaktır .
Lloyd

Yanıtlar:


3920

Kendi karşılaştırma işlevinizi yazmak yeterince kolaydır:

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((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0)); 

441
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


176
return a.last_nom.localeCompare(b.last_nom)de çalışacak.
Cerbrus

146
alanın sayısal olduğu bir tür arayanlar için karşılaştırma işlevi gövdesi: return a.value - b.value;(ASC)
Andre Figueiredo

20
@Cerbrus localeCompare, yabancı dilde aksanlı karakterler kullanırken daha da önemlidir.
Marcos Lima

839

Nesneleri ilettiğiniz değerine göre sıralayan dinamik bir 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) {
        /* next line works with strings and numbers, 
         * and you may want to customize it to your needs
         */
        var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
        return result * sortOrder;
    }
}

Yani bunun gibi bir dizi nesneye sahip olabilirsiniz:

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

... ve bunu yaptığınızda çalışır:

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

Aslında bu zaten soruyu cevaplıyor. Aşağıdaki bölüm yazılmıştır çünkü birçok kişi benimle iletişime geçti, birden fazla parametre ile çalışmadığından şikayet etti .

Çoklu Parametreler

Birden çok sıralama parametresine sahip 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;
    }
}

Hangi böyle bir şey yapmanızı sağlar:

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

Alt Sınıf Dizisi

Aramızdaki yerel nesneleri genişletmeye izin veren ES6'yı kullanabilen şanslılar için:

class MyArray extends Array {
    sortBy(...args) {
        return this.sort(dynamicSortMultiple.apply(null, args));
    }
}

Bu şunları sağlar:

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

JavaScript'teki özellik adlarının herhangi bir dize olabileceğini ve "-" ile başlayan (son derece olası ve muhtemelen iyi bir fikir değil) özelliklere sahipseniz, başka bir şeyi ters sıralama olarak kullanmak için dynamicSort işlevini değiştirmeniz gerektiğini lütfen unutmayın. gösterge.
Ege Özcan

dynamicSort()Yukarıdaki örnekte büyük harflerin küçük harflerin önüne yerleştirileceğini fark ettim . Ben değerlerine sahip Örneğin, APd, Aklin, ve Abe- bir ASC sonuçlanır sıralama olmalı Abe, Aklin, APd. Ama örnek ile, sonuçlarıdır APd, Abe, Aklin. Yine de bu davranışı düzeltmek için?
Lloyd Banks

6
@LloydBanks bunu kesinlikle dizeler için kullanıyorsanız, var result = a[property].localeCompare(b[property]);bunun yerine kullanabilirsiniz var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;.
Ege Özcan

1
@ EgeÖzcan Öğeleri yukarı veya aşağıya koymalı, işte burada kullandığım pastebin.com/g4dt23jU
dzh

1
Bu harika bir çözüm, ancak sayıları karşılaştırırsanız bir sorun var. Lütfen kontrol etmeden önce bunu ekleyin:if( !isNaN(a[property]) ) a[property] = Number(a[property]); if( !isNaN(b[property]) ) b[property] = Number(b[property]);
Ivijan Stefan Stipić

415

ES6 / ES2015 veya sonraki sürümlerde şu şekilde yapabilirsiniz:

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

ES6 / ES2015'ten önce

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

29
bu JS 1.1'den beri mevcut, bunun için şişman ok parçası ES6 / 2015 parçası. Ama yine de çok yararlı ve en iyi cevap bence
Jon Harding

13
@PratikKelwalkar: tersine ihtiyacınız varsa, sadece a ve b karşılaştırmasını değiştirin: objs.sort ((a, b) => b.last_nom.localeCompare (a.last_nom));
Vlad Bezden

sıralama için alanı işaretlemek için de bir dizin kullanmak mümkün mü last_nom: sadece dizideki sayıyı kullanmak yerine:? 1
and-bri

4
@VladBezden Cevabınız için teşekkürler! Bu çözüm, çok küçük programatik çaba ve doğru sıralama sonuçları ve ["Ad1", "Ad10", "Ad2", "başka bir şey", "Ad11"] gibi bir dize dizisi olan ilk çözümdür. Doğru şekilde çalışmak için sıralama yaptımobjs.sort((a, b) => a.last_nom.localeCompare(b.last_nom, undefined, {numberic: true}));
scipper

1
Bunu azalan sayılarla yapmak için: .sort ((a, b) => b.numberProperty - a.numberProperty). Artan: .sort ((a, b) => a.numberProperty - b.numberProperty)
Sebastian Patten

188

underscore.js

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

sortBy_.sortBy (list, iterator, [context]) Her bir değeri yineleyici üzerinden çalıştırma sonuçlarına göre artan düzende sıralanmış, listenin sıralanmış bir kopyasını döndürür. Yineleyici ayrıca, sıralanacak özelliğin dize adı da olabilir (ör. 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' );

18
David, cevabını düzenleyebilir misiniz var sortedObjs = _.sortBy( objs, 'first_nom' );? objsolacak değil bunun sonucu olarak kendini sıralanabilir. İşlev sıralanmış bir dizi döndürür . Bu onu daha açık hale getirir.
Jess

10
Tersine çevirmek için:var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse();
Erdal G.

2
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

5
LodashBunu tercih edenler için de mevcut
WoJ

2
Lodash'da bu aynı olurdu: var sortedObjs = _.sortBy( objs, 'first_nom' );ya da farklı bir sırayla istiyorsanız:var sortedObjs = _.orderBy( objs, ['first_nom'],['dsc'] );
Travis Heeter

186

İnsanların neden bu kadar karmaşık hale getirdiklerini anlamayın:

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

Daha katı 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.


17
Sıralamada kullanılan işlev -1, 0 veya 1 döndürmeli, ancak yukarıdaki işlev bir boole döndürdüğü için bu aslında doğru değildir. Sıralama kromda iyi çalışır ancak örneğin PhantomJS'de başarısız olur. Bkz code.google.com/p/phantomjs/issues/detail?id=1090
schup

Bazı motorlar aptallığı açıklar, bu şekilde bir çeşit sömürü vardı. Cevabımı uygun bir sürümle güncelledim.
p3lim

19
İlk sürümü çıkarmak için düzenlemeyi öneririm. Daha özlü olduğu için daha çekici görünüyor, ancak en azından güvenilir bir şekilde çalışmıyor. Birisi bir tarayıcıda denerse ve çalışırsa, bir sorunu olduğunu bile fark etmeyebilir (özellikle yorumları okumadıysa). İkinci versiyon düzgün çalışıyor, bu yüzden ilk versiyona gerçekten gerek yok.
Kate

2
@Simon daha önce "biraz yanlış" versiyonuna sahip olmayı gerçekten takdir ettim, çü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

1
@ Lion789 sadece şunu yapın:if(a.count == b.count) return a.name > b.name; else return a.count > b.count;
p3lim

62

Yinelenen soyadınız varsa, bunları ilk ada göre 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;
});

@BadFeelingAboutBu -1 veya 1 döndürmek ne anlama geliyor? -1'in tam anlamıyla A'nın sadece sözdizimi ile B'den küçük olduğu anlamına geldiğini anlıyorum, ama neden 1 veya -1 kullanıyorsunuz? Herkesin bu sayıları dönüş değerleri olarak kullandığını görüyorum, ama neden? Teşekkürler.
Chris22

1
@ Chris22 negatif bir sayı döndürülür anlamına gelir dizide bsonra gelmelidir a. Pozitif bir sayı döndürülürse, asonra gelmelidir b. Eğer 0iade edilirse , eşit kabul edildikleri anlamına gelir. Belgeleri her zaman okuyabilirsiniz: developer.mozilla.org/tr-TR/docs/Web/JavaScript/Reference/…
BadFeelingAboutThis

@BadFeelingAboutBu teşekkürler, açıklama ve bağlantı için. İster inanın ister inanmayın, bunu burada sormadan 1, 0, -1önce çeşitli kod snippet'lerini kullandım . Sadece ihtiyacým olan bilgiyi bulamadým.
Chris22

48

Prototip mirasını kullanarak bu soruna basit ve hızlı bir çö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üncelleme: Artık orijinal diziyi değiştirmiyor.


5
Sadece başka bir dizi döndürmez. ama aslında orijinali sıralar !.
Vinay Aggarwal

Rakamlarla doğal bir sıralama kullandığınızdan emin olmak istiyorsanız (örn. 0,1,2,10,11 vb.) Radix seti ile parseInt kullanın. developer.mozilla.org/tr-TR/docs/Web/JavaScript/Reference/… so: return (parseInt (a [p], 10)> parseInt (b [p], 10))? 1: (parseInt (a [p], 10) <parseInt (b [p], 10))? -1: 0;
Paul

@codehuntr Düzelttiğiniz için teşekkürler. ancak bu hassaslaştırmayı yapmak için sıralama işlevi yapmak yerine, veri türlerini düzeltmek için ayrı bir işlev yaparsak daha iyi olur. Çünkü sort işlevi, hangi özelliğin ne tür veriler içereceğini söyleyemez. :)
Vinay Aggarwal

Çok hoş. Artan / azalan efekti elde etmek için okları ters çevirin.
Abdul Sadik Yalçın

4
asla, asla çekirdek bir nesnenin prototipini değiştiren bir çözüm önermeyin
pbanka

39

2018 itibariyle çok daha kısa ve zarif bir çözüm var. Sadece kullan. Array.prototype.sort () .

Misal:

var items = [
  { name: 'Edward', value: 21 },
  { name: 'Sharpe', value: 37 },
  { name: 'And', value: 45 },
  { name: 'The', value: -12 },
  { name: 'Magnetic', value: 13 },
  { name: 'Zeros', value: 37 }
];

// sort by value
items.sort(function (a, b) {
  return a.value - b.value;
});

7
Soruda sayıların aksine karşılaştırma için dizeler kullanıldı. Cevabınız sayılara göre sıralamak için harika çalışıyor, ancak dizeye göre karşılaştırmalar için iyi değil.
smcstewart

a.value - b.valueNesnenin özelliklerini (karşılaştırmak için kullanılan sayılar bu durumda) verilerin çeşitli zamanlar için kabul edilebilir. Örneğin, regex, komşu dizelerin her bir çiftini karşılaştırmak için kullanılabilir .
0leg

1
@ 0leg Burada dizeleri bu şekilde karşılaştırmak için regex kullanarak bir örnek görmek istiyorum.
Bob Stein

Bu uygulama kimliğe göre sıralamanız gerekiyorsa oldukça iyidir. Evet, çözümü daha karmaşık hale getiren komşu dizeyi karşılaştırmak için regex kullanmanızı önermişken, regex verilen çözümle birlikte kullanıldığında bu basitleştirilmiş sürümün amacı aksi olacaktır. Sadelik en iyisidir.
surendrapanday

33

Doğru olmayan eski cevap:

arr.sort((a, b) => a.name > b.name)

GÜNCELLEME

Beauchamp'ın yorumundan:

arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))

Daha okunabilir format:

arr.sort((a, b) => {
  if (a.name < b.name) return -1
  return a.name > b.name ? 1 : 0
})

Yuvalanmış üçlüler olmadan:

arr.sort((a, b) => a.name < b.name ? - 1 : Number(a.name > b.name))

Açıklama: Number()kullanacaklar trueiçin 1ve falseiçin 0.


Çalışıyor, ancak sonuç bir nedenden dolayı kararsız
TitanFighter

@ AO17 hayır olmayacak. Dizeleri çıkaramazsınız.
Patrick Roberts

15
Bunu yapmalı:arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))
Jean-François Beauchamp

3
@ Jean-FrançoisBeauchamp, çözümünüz gayet iyi ve çok daha iyi çalışıyor.
Ahsan

Sayı ile 3. bir basit ve güzel!
Kojo

29

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

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

29

Lodash.js ( Underscore.js'nin üst kümesi )

Her basit mantık parçası için bir çerçeve eklememek iyidir, ancak iyi test edilmiş yardımcı program çerçevelerine güvenmek gelişimi hızlandırabilir ve hata miktarını azaltabilir.

Lodash çok temiz bir kod üretir ve daha işlevsel bir programlama tarzı sağlar. Bir bakışta, kodun amacının ne olduğu netleşir.

OP'nin sorunu şu şekilde çözülebilir:

const sortedObjs = _.sortBy(objs, 'last_nom');

Daha fazla bilgi? Örneğin aşağıdaki iç içe nesnelerimiz var:

const users = [
  { 'user': {'name':'fred', 'age': 48}},
  { 'user': {'name':'barney', 'age': 36 }},
  { 'user': {'name':'wilma'}},
  { 'user': {'name':'betty', 'age': 32}}
];

Şimdi _.property kısayolunu user.agekullanarak eşleştirilmesi gereken özelliğin yolunu belirtebiliriz. Kullanıcı nesnelerini iç içe yaş özelliğine göre sıralayacağız. Evet, yuvalanmış özellik eşleşmesine izin verir!

const sortedObjs = _.sortBy(users, ['user.age']);

Tersine çevirmek mi istiyorsunuz? Sorun değil. _.Reverse kullanın .

const sortedObjs = _.reverse(_.sortBy(users, ['user.age']));

Her iki zinciri kullanarak birleştirmek ister misiniz ?

const { chain } = require('lodash');
const sortedObjs = chain(users).sortBy('user.age').reverse().value();

Veya ne zaman zincir üzerinden akışı tercih edersiniz

const { flow, reverse, sortBy } = require('lodash/fp');
const sortedObjs = flow([sortBy('user.age'), reverse])(users); 

28

Kullanabilirsiniz

En Kolay Yol: Lodash

( https://lodash.com/docs/4.17.10#orderBy )

Bu yöntem _.sortBy gibidir, ancak yinelemelerin sıralama düzenine göre sıralanmasına izin verir. Siparişler belirtilmezse, tüm değerler artan sırada sıralanır. Aksi takdirde, azalan değer için "azalan" veya karşılık gelen değerlerin artan sıralama için "artan" sırasını belirtin.

Argümanlar

collection (Array | Object): Üzerinde yinelenecek koleksiyon. [iteratees = [_. identity]] (Dizi [] | İşlev [] | Nesne [] | string []): Sıralama ölçütü olarak tekrarlanır. [orders] (string []): Yinelemelerin sıralama düzenleri.

İadeler

(Array): Sıralanan yeni diziyi döndürür.


var _ = require('lodash');
var homes = [
    {"h_id":"3",
     "city":"Dallas",
     "state":"TX",
     "zip":"75201",
     "price":"162500"},
    {"h_id":"4",
     "city":"Bevery Hills",
     "state":"CA",
     "zip":"90210",
     "price":"319250"},
    {"h_id":"6",
     "city":"Dallas",
     "state":"TX",
     "zip":"75000",
     "price":"556699"},
    {"h_id":"5",
     "city":"New York",
     "state":"NY",
     "zip":"00010",
     "price":"962500"}
    ];

_.orderBy(homes, ['city', 'state', 'zip'], ['asc', 'desc', 'asc']);

23

Burada çok iyi cevaplar var, ancak çok daha karmaşık bir sıralama elde etmek için çok basit bir şekilde genişletilebileceğini belirtmek isterim. Yapmanız gereken tek şey, OR işlevini, aşağıdaki gibi karşılaştırma işlevlerini zincirlemek için kullanmaktır:

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

Burada fn1,, fn2... [-1,0,1] döndüren sıralama işlevleridir. Bu, SQL'de ORDER BY'a hemen hemen eşit olan "fn1 ile sıralama", "fn2 ile sıralama" ile sonuçlanır.

Bu çözüm, doğruya dönüştürülebilen ilk değerlendirilen ifadeyi|| değerlendiren operatörün davranışına dayanır .

En basit formun sadece tek bir satır içi 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_nomsıralama düzenini şu şekilde görünecektir:

// 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 şöyle 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ı, arbiter veri tiplerini vb. Desteklemek için genişletilebilir.

Sıralama önceliğine göre zincirleme ile kullanabilirler:

// 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şıma sahip saf JavaScript'in harici kütüphaneler veya karmaşık kod olmadan sizi uzun bir yol alabileceğidir. Aynı zamanda çok etkilidir, çünkü dize ayrıştırma yapılmasına gerek yoktur


23

Örnek Kullanım:

objs.sort(sortBy('last_nom'));

Senaryo:

/**
 * @description
 * Returns a function which will sort an
 * array of objects by the given key.
 *
 * @param  {String}  key
 * @param  {Boolean} reverse
 * @return {Function}
 */
const sortBy = (key, reverse) => {

  // Move smaller items towards the front
  // or back of the array depending on if
  // we want to sort the array in reverse
  // order or not.
  const moveSmaller = reverse ? 1 : -1;

  // Move larger items towards the front
  // or back of the array depending on if
  // we want to sort the array in reverse
  // order or not.
  const moveLarger = reverse ? -1 : 1;

  /**
   * @param  {*} a
   * @param  {*} b
   * @return {Number}
   */
  return (a, b) => {
    if (a[key] < b[key]) {
      return moveSmaller;
    }
    if (a[key] > b[key]) {
      return moveLarger;
    }
    return 0;
  };
};

Bunu yıktığınız için teşekkür ederim, basamakların neden 1, 0, -1sıralama düzeni için kullanıldığını anlamaya çalışıyorum . Yukarıdaki açıklamanızla bile, çok iyi görünüyor - hala tam olarak anlayamıyorum. Her zaman -1dizi uzunluğu özelliğini kullanırken, yani: arr.length = -1öğe bulunamadı anlamına gelir düşünüyorum. Muhtemelen burada bir şeyler karıştırıyorum, ama 1, 0, -1sıraları belirlemek için basamakların neden kullanıldığını anlamama yardımcı olabilir misiniz ? Teşekkürler.
Chris22

1
Bu tamamen doğru değildir, ancak böyle düşünmeye yardımcı olabilir: array.sort'a iletilen işlev, dizideki her öğe için, "a" adlı bağımsız değişken olarak bir kez çağrılır. Her işlev çağrısının dönüş değeri, "a" öğesinin dizininin (geçerli konum numarası) bir sonraki "b" öğesine göre nasıl değiştirilmesi gerektiğidir. Dizin, dizinin sırasını belirler (0, 1, 2 vb.) Eğer "a" dizin 5'te ise ve -1 döndürürseniz 5 + -1 == 4 (öne yaklaş) 5 + 0 == 5 Sıralı bir dizi bırakarak sona ulaşana kadar her seferinde 2 komşuyu karşılaştıran dizide yürür.
Jamie Mason

Bunu daha fazla açıklamak için zaman ayırdığınız için teşekkür ederiz. Yani açıklama ve kullanma MDN Array.prototype.sort karşılaştırıldığında: ben bu düşünüyorum ne anlatacağım ave beğer adaha büyüktür bendeksine ekleme 1 ave arkasında bir yerde onu beğer, adaha az olduğunu b, 1 adeğerini çıkarın ve önüne yerleştirin b. Eğer ave baynı, için 0 rakamını ekleyin ave nerede olduğunu bırakın.
Chris22

22

Bu özel yaklaşımın önerildiğini görmedim, bu yüzden her ikisi için de işe yarayan kısa bir karşılaştırma yöntemi stringve number:

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

const sortBy = fn => (a, b) => {
  const fa = fn(a);
  const fb = fn(b);
  return -(fa < fb) || +(fa > fb);
};

const getLastName = o => o.last_nom;
const sortByLastName = sortBy(getLastName);

objs.sort(sortByLastName);
console.log(objs.map(getLastName));

İşte bir açıklama sortBy():

sortBy()kabul eden bir fnNesneden hangi değeri seçer karşılaştırma ve dönüş doğrudan geçirilebilir bir fonksiyonu olarak kullanmak için bu Array.prototype.sort(). Bu örnekte, o.last_nomkarşılaştırma için değer olarak kullanıyoruz , bu nedenle aşağıdaki Array.prototype.sort()gibi iki nesne aldığımızda

{ first_nom: 'Lazslo', last_nom: 'Jamf' }

ve

{ first_nom: 'Pig', last_nom: 'Bodine' }

kullanırız

(a, b) => {
  const fa = fn(a);
  const fb = fn(b);
  return -(fa < fb) || +(fa > fb);
};

karşılaştırmak için.

Bunu hatırlayarak fn = o => o.last_nomkarşılaştırma işlevini eşdeğerine genişletebiliriz

(a, b) => {
  const fa = a.last_nom;
  const fb = b.last_nom;
  return -(fa < fb) || +(fa > fb);
};

Mantıksal OR ||operatörü, burada çok yararlı olan kısa devre işlevselliğine sahiptir. Nasıl çalıştığı nedeniyle, yukarıdaki fonksiyonun gövdesi şu anlama gelir:

if (fa < fb) return -1;
if (fa > fb) return 1;
return 0;

Ek bir bonus olarak, maalesef daha ayrıntılı olan ECMAScript 5'in ok işlevleri olmayan eşdeğeri:

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

var sortBy = function (fn) {
  return function (a, b) {
    var fa = fn(a);
    var fb = fn(b);
    return -(fa < fb) || +(fa > fb);
  };
};

var getLastName = function (o) { return o.last_nom };
var sortByLastName = sortBy(getLastName);

objs.sort(sortByLastName);
console.log(objs.map(getLastName));


17

Bu sorunun çok eski olduğunu biliyorum, ama benimkine benzer bir uygulama görmedim.
Bu sürüm Schwartz dönüşümünü temel almaktadır .

function sortByAttribute(array, ...attrs) {
  // generate an array of predicate-objects contains
  // property getter, and descending indicator
  let predicates = attrs.map(pred => {
    let descending = pred.charAt(0) === '-' ? -1 : 1;
    pred = pred.replace(/^-/, '');
    return {
      getter: o => o[pred],
      descend: descending
    };
  });
  // schwartzian transform idiom implementation. aka: "decorate-sort-undecorate"
  return array.map(item => {
    return {
      src: item,
      compareValues: predicates.map(predicate => predicate.getter(item))
    };
  })
  .sort((o1, o2) => {
    let i = -1, result = 0;
    while (++i < predicates.length) {
      if (o1.compareValues[i] < o2.compareValues[i]) result = -1;
      if (o1.compareValues[i] > o2.compareValues[i]) result = 1;
      if (result *= predicates[i].descend) break;
    }
    return result;
  })
  .map(item => item.src);
}

İşte nasıl kullanılacağına dair bir örnek:

let games = [
  { name: 'Mashraki',          rating: 4.21 },
  { name: 'Hill Climb Racing', rating: 3.88 },
  { name: 'Angry Birds Space', rating: 3.88 },
  { name: 'Badland',           rating: 4.33 }
];

// sort by one attribute
console.log(sortByAttribute(games, 'name'));
// sort by mupltiple attributes
console.log(sortByAttribute(games, '-rating', 'name'));

14

Sıralama (daha fazla) Nesnelerin Karmaşık Dizileri

Muhtemelen bu dizi gibi daha karmaşık veri yapılarıyla karşılaştığınız için çözümü genişletirim.

TL; DR

@ Ege-Özcan'ın çok güzel cevabını temel alan daha geçmeli versiyonlardır .

Sorun

Aşağıdakilerle karşılaştım ve değiştiremedim. Ayrıca nesneyi geçici olarak düzleştirmek istemedim. Ben de alt çizgi / lodash kullanmak istemedim, temelde performans nedenleriyle ve bunu kendim uygulamak için eğlenceli.

var People = [
   {Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
   {Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
   {Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];

Hedef

Amaç, öncelikle People.Name.nameve ikincil olarakPeople.Name.surname

Engeller

Şimdi, temel çözüm dinamik olarak sıralamak için özellikleri hesaplamak için köşeli ayraç gösterimi kullanır. Bununla birlikte, burada, braket gösterimini dinamik olarak da inşa etmek zorundayız, çünkü bazılarının People['Name.name']işe yaramasını beklersiniz - ki bu işe yaramaz.

People['Name']['name']Öte yandan, basitçe yapmak statiktir ve sadece n. Seviyeye inmenizi sağlar.

Çözüm

Buradaki ana ekleme, nesne ağacından aşağı inmek ve herhangi bir ara yaprağın yanı sıra belirtmeniz gereken son yaprağın değerini belirlemek olacaktır.

var People = [
   {Name: {name: "Name", surname: "Surname"}, Middlename: "JJ"},
   {Name: {name: "AAA", surname: "ZZZ"}, Middlename:"Abrams"},
   {Name: {name: "Name", surname: "AAA"}, Middlename: "Wars"}
];

People.sort(dynamicMultiSort(['Name','name'], ['Name', '-surname']));
// Results in...
// [ { Name: { name: 'AAA', surname: 'ZZZ' }, Middlename: 'Abrams' },
//   { Name: { name: 'Name', surname: 'Surname' }, Middlename: 'JJ' },
//   { Name: { name: 'Name', surname: 'AAA' }, Middlename: 'Wars' } ]

// same logic as above, but strong deviation for dynamic properties 
function dynamicSort(properties) {
  var sortOrder = 1;
  // determine sort order by checking sign of last element of array
  if(properties[properties.length - 1][0] === "-") {
    sortOrder = -1;
    // Chop off sign
    properties[properties.length - 1] = properties[properties.length - 1].substr(1);
  }
  return function (a,b) {
    propertyOfA = recurseObjProp(a, properties)
    propertyOfB = recurseObjProp(b, properties)
    var result = (propertyOfA < propertyOfB) ? -1 : (propertyOfA > propertyOfB) ? 1 : 0;
    return result * sortOrder;
  };
}

/**
 * Takes an object and recurses down the tree to a target leaf and returns it value
 * @param  {Object} root - Object to be traversed.
 * @param  {Array} leafs - Array of downwards traversal. To access the value: {parent:{ child: 'value'}} -> ['parent','child']
 * @param  {Number} index - Must not be set, since it is implicit.
 * @return {String|Number}       The property, which is to be compared by sort.
 */
function recurseObjProp(root, leafs, index) {
  index ? index : index = 0
  var upper = root
  // walk down one level
  lower = upper[leafs[index]]
  // Check if last leaf has been hit by having gone one step too far.
  // If so, return result from last step.
  if (!lower) {
    return upper
  }
  // Else: recurse!
  index++
  // HINT: Bug was here, for not explicitly returning function
  // https://stackoverflow.com/a/17528613/3580261
  return recurseObjProp(lower, leafs, index)
}

/**
 * Multi-sort your array by a set of properties
 * @param {...Array} Arrays to access values in the form of: {parent:{ child: 'value'}} -> ['parent','child']
 * @return {Number} Number - number for sort algorithm
 */
function dynamicMultiSort() {
  var args = Array.prototype.slice.call(arguments); // slight deviation to base

  return function (a, b) {
    var i = 0, result = 0, numberOfProperties = args.length;
    // REVIEW: slightly verbose; maybe no way around because of `.sort`-'s nature
    // Consider: `.forEach()`
    while(result === 0 && i < numberOfProperties) {
      result = dynamicSort(args[i])(a, b);
      i++;
    }
    return result;
  }
}

Misal

JSBin üzerinde çalışma örneği


2
Neden? Bu orijinal sorunun cevabı değildir ve "hedef" sadece People.sort ((a, b) => {return a.Name.name.localeCompare (b.Name.name) || a.Name ile çözülebilir .surname.localeCompare (b.Name.surname)})
Tero Tolonen

12

Bir seçenek daha:

var someArray = [...];

function generateSortFn(prop, reverse) {
    return function (a, b) {
        if (a[prop] < b[prop]) return reverse ? 1 : -1;
        if (a[prop] > b[prop]) return reverse ? -1 : 1;
        return 0;
    };
}

someArray.sort(generateSortFn('name', true));

varsayılan olarak artan sıralar.


1
Birden fazla alana göre sıralama için biraz değiştirilmiş sürüm gerekirse: stackoverflow.com/questions/6913512/…
Ravshan Samandarov

sıradaki gibi görünebilir: export işlevi createSortFn (prop: string, reverse: boolean = false): (... args: any) => sayı {return (a, b) => {a [prop döndür ] <b [destek]? tersine çevirmek ? 1: -1: a [prop]? tersine çevirmek ? -1: 1: 0; }; }
Den Kerny

En kısa olandan daha okunabilir kodu tercih ederim.
Ravshan Samandarov

kabul etti, ancak bazı durumlarda yardımcı program işlevlerine bakmaya ihtiyacım yok.
Den Kerny

11

Bir nesne dizisini bir özelliğe göre sıralayan basit bir işlev

function sortArray(array, property, direction) {
    direction = direction || 1;
    array.sort(function compare(a, b) {
        let comparison = 0;
        if (a[property] > b[property]) {
            comparison = 1 * direction;
        } else if (a[property] < b[property]) {
            comparison = -1 * direction;
        }
        return comparison;
    });
    return array; // Chainable
}

Kullanımı:

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

sortArray(objs, "last_nom"); // Asc
sortArray(objs, "last_nom", -1); // Desc

Bu çözüm iki yönlü sıralama yapmak için mükemmel çalıştı. Thank u
manjuvreddy

10

Basit bir yol:

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

'.toLowerCase()'Dizeleri karşılaştırırken hataların önlenmesi için gerekli olduğuna bakın .


4
Kodun biraz daha zarif olmasını sağlamak için ok işlevlerini kullanabilirsiniz :objs.sort( (a,b) => b.last_nom.toLowerCase() < a.last_nom.toLowerCase() );
Sergin

Burada açıklananla aynı nedenden dolayı bu yanlıştır .
Patrick Roberts

2
Ok işlevleri ES5'e layık değildir. Tonlarca motor hala ES5 ile sınırlıdır. Benim durumumda, bir ES5 motorunda (şirketim tarafından zorla) bulunduğumdan yukarıdaki cevabı çok daha iyi buluyorum
dylanh724

9

Ege Özcan kodu için ek parametreler

function dynamicSort(property, desc) {
    if (desc) {
        return function (a, b) {
            return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
        }   
    }
    return function (a, b) {
        return (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
    }
}

9

Ege'nin dinamik çözümünü Vinay'ın fikri ile birleştirerek güzel ve sağlam bir çözüm elde edersiniz:

Array.prototype.sortBy = function() {
    function _sortByAttr(attr) {
        var sortOrder = 1;
        if (attr[0] == "-") {
            sortOrder = -1;
            attr = attr.substr(1);
        }
        return function(a, b) {
            var result = (a[attr] < b[attr]) ? -1 : (a[attr] > b[attr]) ? 1 : 0;
            return result * sortOrder;
        }
    }
    function _getSortFunc() {
        if (arguments.length == 0) {
            throw "Zero length arguments not allowed for Array.sortBy()";
        }
        var args = arguments;
        return function(a, b) {
            for (var result = 0, i = 0; result == 0 && i < args.length; i++) {
                result = _sortByAttr(args[i])(a, b);
            }
            return result;
        }
    }
    return this.sort(_getSortFunc.apply(null, arguments));
}

Kullanımı:

// Utility for printing objects
Array.prototype.print = function(title) {
    console.log("************************************************************************");
    console.log("**** "+title);
    console.log("************************************************************************");
    for (var i = 0; i < this.length; i++) {
        console.log("Name: "+this[i].FirstName, this[i].LastName, "Age: "+this[i].Age);
    }
}

// Setup sample data
var arrObj = [
    {FirstName: "Zach", LastName: "Emergency", Age: 35},
    {FirstName: "Nancy", LastName: "Nurse", Age: 27},
    {FirstName: "Ethel", LastName: "Emergency", Age: 42},
    {FirstName: "Nina", LastName: "Nurse", Age: 48},
    {FirstName: "Anthony", LastName: "Emergency", Age: 44},
    {FirstName: "Nina", LastName: "Nurse", Age: 32},
    {FirstName: "Ed", LastName: "Emergency", Age: 28},
    {FirstName: "Peter", LastName: "Physician", Age: 58},
    {FirstName: "Al", LastName: "Emergency", Age: 51},
    {FirstName: "Ruth", LastName: "Registration", Age: 62},
    {FirstName: "Ed", LastName: "Emergency", Age: 38},
    {FirstName: "Tammy", LastName: "Triage", Age: 29},
    {FirstName: "Alan", LastName: "Emergency", Age: 60},
    {FirstName: "Nina", LastName: "Nurse", Age: 54}
];

//Unit Tests
arrObj.sortBy("LastName").print("LastName Ascending");
arrObj.sortBy("-LastName").print("LastName Descending");
arrObj.sortBy("LastName", "FirstName", "-Age").print("LastName Ascending, FirstName Ascending, Age Descending");
arrObj.sortBy("-FirstName", "Age").print("FirstName Descending, Age Ascending");
arrObj.sortBy("-Age").print("Age Descending");

1
Fikir için teşekkürler! Bu arada, lütfen insanları Dizi Prototipini değiştirmeye teşvik etmeyin (örneğimin sonundaki uyarıya bakın).
Ege Özcan

8

Örneğinize göre, bir alan yerine iki alana (soyadı, adı) göre sıralamanız gerekir. Alasql kütüphanesini bu sıralamayı bir satırda yapmak için kullanabilirsiniz :

var res = alasql('SELECT * FROM ? ORDER BY last_nom, first_nom',[objs]);

Bu örneği jsFiddle'da deneyin .


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

1
Aslında işe yaramadı, kabul edilen cevabı kullanmak zorunda kaldı. Doğru sıralama yapmıyordu.
madprops

8

Orijinal örnek göz önüne alındığında:

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

Birden çok alana göre sırala:

objs.sort(function(left, right) {
    var last_nom_order = left.last_nom.localeCompare(right.last_nom);
    var first_nom_order = left.first_nom.localeCompare(right.first_nom);
    return last_nom_order || first_nom_order;
});

notlar

  • a.localeCompare(b)olduğu evrensel olarak desteklenen ve döner -1,0,1 eğer a<b, a==b, a>bsırasıyla.
  • ||son satırda last_nomöncelik verilir first_nom.
  • Çıkarma sayısal alanlarda çalışır: var age_order = left.age - right.age;
  • Sırayı tersine çevirmek, return -last_nom_order || -first_nom_order || -age_order;

8

Bunu dene,

UPTO ES5

//Ascending Sort
items.sort(function (a, b) {
   return a.value - b.value;
});


//Descending Sort
items.sort(function (a, b) {
   return b.value - a.value;
});


IN ES6 & above:

// Ascending sort
items.sort((a, b) => a.value - b.value);

// Descending Sort
 items.sort((a, b) => b.value - a.value);

en iyi ve kolay çözüm
Omar Hasan

7

Karışıklığı önlemek için bunları küçük harfe dönüştürmeniz gerekebilir.

objs.sort(function (a,b) {

var nameA=a.last_nom.toLowerCase(), nameB=b.last_nom.toLowerCase()

if (nameA < nameB)
  return -1;
if (nameA > nameB)
  return 1;
return 0;  //no sorting

})

7
function compare(propName) {
    return function(a,b) {
        if (a[propName] < b[propName])
            return -1;
        if (a[propName] > b[propName])
            return 1;
        return 0;
    };
}

objs.sort(compare("last_nom"));

1
Kodunuzun ne yaptığına ve sorunun neden çözüleceğine ilişkin daha fazla açıklama eklemek için lütfen yayınınızı düzenleyin. Çoğunlukla sadece kod içeren bir yanıt (çalışıyor olsa bile) genellikle OP'nin sorunlarını anlamalarına yardımcı olmaz.
Drenmi

7

Ramda kullanarak,

npm yükleme ramda

import R from 'ramda'
var objs = [ 
    { first_nom: 'Lazslo', last_nom: 'Jamf'     },
    { first_nom: 'Pig',    last_nom: 'Bodine'   },
    { first_nom: 'Pirate', last_nom: 'Prentice' }
];
var ascendingSortedObjs = R.sortBy(R.prop('last_nom'), objs)
var descendingSortedObjs = R.reverse(ascendingSortedObjs)

6

Bu basit bir sorundur, insanların neden bu kadar karmaşık bir çözümü olduğunu bilmiyorum.
Basit bir sıralama işlevi ( hızlı sıralama algoritmasına dayalı ):

function sortObjectsArray(objectsArray, sortKey)
        {
            // Quick Sort:
            var retVal;

            if (1 < objectsArray.length)
            {
                var pivotIndex = Math.floor((objectsArray.length - 1) / 2);  // middle index
                var pivotItem = objectsArray[pivotIndex];                    // value in the middle index
                var less = [], more = [];

                objectsArray.splice(pivotIndex, 1);                          // remove the item in the pivot position
                objectsArray.forEach(function(value, index, array)
                {
                    value[sortKey] <= pivotItem[sortKey] ?                   // compare the 'sortKey' proiperty
                        less.push(value) :
                        more.push(value) ;
                });

                retVal = sortObjectsArray(less, sortKey).concat([pivotItem], sortObjectsArray(more, sortKey));
            }
            else
            {
                retVal = objectsArray;
            }

            return retVal;
        }

Örnek kullanın:

var myArr = 
        [
            { val: 'x', idx: 3 },
            { val: 'y', idx: 2 },
            { val: 'z', idx: 5 },
        ];
myArr = sortObjectsArray(myArr, 'idx');

5
Js hızlı sıralama uygulamak nasıl basit bir çözümdür? Basit algoritma ama basit bir çözüm değil.
Andrew

Herhangi bir dış kütüphane kullanmadığı ve nesnenin prototipini değiştirmediği için basit. Kanımca, kodun uzunluğunun kodun karmaşıklığı üzerinde doğrudan bir etkisi yoktur
Gil Epshtain

2
Farklı kelimelerle deneyeyim: Tekerleği nasıl yeniden icat etmek basit bir çözüm?
Roberto14
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.