เรียงลำดับอาร์เรย์ของวัตถุตามค่าคุณสมบัติสตริง


2763

ฉันมีอาร์เรย์ของวัตถุ JavaScript:

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

ฉันจะเรียงลำดับตามค่าlast_nomใน JavaScript ได้อย่างไร?

ฉันรู้sort(a,b)แต่ดูเหมือนว่าจะใช้กับสตริงและตัวเลขเท่านั้น ฉันจำเป็นต้องเพิ่มtoString()วิธีการในวัตถุของฉันหรือไม่?


7
สคริปต์นี้จะช่วยให้คุณทำเพียงแค่ว่าถ้าคุณต้องการที่จะเขียนฟังก์ชั่นของคุณเองหรือเปรียบเทียบตัวเรียงลำดับ: thomasfrank.se/sorting_things.html
Baversjo

วิธีที่เร็วที่สุดคือการใช้โมดูลเรียงลำดับ isomorphic ซึ่งทำงานได้ทั้งในเบราว์เซอร์และโหนดสนับสนุนการป้อนข้อมูลทุกประเภทฟิลด์คำนวณและคำสั่งการเรียงลำดับแบบกำหนดเอง
Lloyd

คำตอบ:


3920

มันง่ายพอที่จะเขียนฟังก์ชั่นการเปรียบเทียบของคุณเอง:

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

หรืออินไลน์ (c / o Marco Demaio):

objs.sort((a,b) => (a.last_nom > b.last_nom) ? 1 : ((b.last_nom > a.last_nom) ? -1 : 0)); 

441
หรืออินไลน์: objs.sort (ฟังก์ชั่น (a, b) {return (a.last_nom> b.last_nom)? 1: ((b.last_nom> a.last_nom)? -1: 0);});
Marco Demaio

35
เอกสารอย่างเป็นทางการ: developer.mozilla.org/en/JavaScript/Reference/Global_Objects/ …
mikemaccana

176
return a.last_nom.localeCompare(b.last_nom)จะทำงานด้วย
Cerbrus

146
สำหรับผู้ที่กำลังมองหาการเรียงลำดับที่สนามเป็นตัวเลขร่างกายฟังก์ชั่นการเปรียบเทียบ: return a.value - b.value;(ASC)
Andre Figueiredo

20
@Cerbrus localeCompareเป็นสิ่งสำคัญเมื่อใช้อักขระเน้นเสียงในภาษาต่างประเทศและสง่างามมากขึ้นเช่นกัน
Marcos Lima

839

นอกจากนี้คุณยังสามารถสร้างฟังก์ชั่นการจัดเรียงแบบไดนามิกที่ประเภทวัตถุโดยค่าของพวกเขาที่คุณผ่าน:

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

ดังนั้นคุณสามารถมีอาร์เรย์ของวัตถุดังนี้:

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

... และมันจะทำงานเมื่อคุณ:

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

จริงๆแล้วนี่ตอบคำถามแล้ว ด้านล่างเป็นส่วนหนึ่งที่เขียนเพราะหลายคนติดต่อผมบ่นว่ามันไม่ได้ทำงานกับหลายพารามิเตอร์

หลายพารามิเตอร์

คุณสามารถใช้ฟังก์ชั่นด้านล่างเพื่อสร้างฟังก์ชั่นการจัดเรียงด้วยพารามิเตอร์การจัดเรียงหลาย

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

ซึ่งจะช่วยให้คุณทำสิ่งนี้:

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

อาร์เรย์คลาสย่อย

สำหรับผู้โชคดีในหมู่พวกเราที่สามารถใช้ ES6 ซึ่งอนุญาตให้ขยายวัตถุพื้นเมือง:

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

ที่จะเปิดใช้งานสิ่งนี้:

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

โปรดทราบว่าชื่อคุณสมบัติใน JavaScript สามารถเป็นสตริงใดก็ได้และหากคุณมีคุณสมบัติที่ขึ้นต้นด้วย "-" (ไม่น่าจะเป็นไปได้อย่างยิ่งและอาจไม่ใช่ความคิดที่ดี) คุณจะต้องแก้ไขฟังก์ชั่น dynamicSort เพื่อใช้อย่างอื่น ตัวบ่งชี้
Ege Özcan

ฉันสังเกตเห็นว่าdynamicSort()ในตัวอย่างข้างต้นจะวางตัวอักษรพิมพ์ใหญ่ก่อนตัวพิมพ์เล็ก ตัวอย่างเช่นถ้าฉันมีค่าAPd, AklinและAbe- ผลใน ASC เรียงควรจะAbe, ,Aklin APdแต่ด้วยตัวอย่างของผลลัพธ์ที่APd, ,Abe Aklinยังไงก็ตามเพื่อแก้ไขพฤติกรรมนี้?
Lloyd Banks

6
@LloydBanks ถ้าคุณใช้สิ่งนี้อย่างเคร่งครัดสำหรับสตริงคุณสามารถใช้var result = a[property].localeCompare(b[property]);แทนvar result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;ได้
Ege Özcan

1
@ EgeÖzcanมันควรใส่ไอเท็มไปที่ด้านบนหรือด้านล่างนี่คือการใช้งานที่ฉันได้ลงเอยด้วยการใช้pastebin.com/g4dt23jU
dzh

1
นี่คือทางออกที่ดี แต่มีปัญหาหนึ่งถ้าคุณเปรียบเทียบตัวเลข โปรดเพิ่มสิ่งนี้ก่อนตรวจสอบ:if( !isNaN(a[property]) ) a[property] = Number(a[property]); if( !isNaN(b[property]) ) b[property] = Number(b[property]);
Ivijan Stefan Stipić

415

ใน ES6 / ES2015 หรือใหม่กว่าคุณสามารถทำสิ่งนี้ได้:

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

ก่อน ES6 / ES2015

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

29
มีให้บริการตั้งแต่ JS 1.1 ชิ้นส่วนลูกศรอ้วนของชิ้นนี้คือ ES6 / 2015 แต่ก็ยังมีประโยชน์มากและเป็นคำตอบที่ดีที่สุดในความคิดของฉัน
Jon Harding

13
@PratikKelwalkar: หากคุณต้องการสลับมันเพียงแค่สลับ a และ b การเปรียบเทียบ: objs.sort ((a, b) => b.last_nom.localeCompare (a.last_nom));
Vlad Bezden

มันเป็นไปได้ที่จะใช้ดัชนีเช่นกันเพื่อแก้ไขเขตข้อมูลสำหรับการเรียงลำดับ: แทนการlast_nomใช้เพียงตัวเลขในอาร์เรย์: 1?
และ - bri

4
@VladBezden ขอบคุณสำหรับคำตอบของคุณ! วิธีนี้เป็นโซลูชั่นแรกที่มีความพยายามทางโปรแกรมน้อยมากและผลลัพธ์การเรียงลำดับที่ถูกต้องและอาร์เรย์สตริงเช่น: ["Name1", "Name10", "Name2", "อย่างอื่น", "Name11"] ฉันได้เรียงลำดับเพื่อทำงานอย่างถูกต้องกับobjs.sort((a, b) => a.last_nom.localeCompare(b.last_nom, undefined, {numberic: true}));
scipper

1
เมื่อต้องการทำสิ่งนี้ด้วยตัวเลขจากมากไปน้อย: .sort ((a, b) => b.numberProperty - a.numberProperty) จากน้อยไปมาก: .sort ((a, b) => a.numberProperty - b.numberProperty)
Sebastian Patten

188

underscore.js

ใช้ขีดล่างมีขนาดเล็กและยอดเยี่ยม ...

sortBy_.sortBy (list, iterator, [context]) ส่งคืนสำเนาเรียงลำดับของรายการเรียงลำดับจากน้อยไปหามากโดยผลลัพธ์ของการรันแต่ละค่าผ่านตัววนซ้ำ Iterator อาจเป็นชื่อสตริงของคุณสมบัติที่จะเรียงลำดับ (เช่นความยาว)

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
เดวิดคุณช่วยแก้ไขคำตอบที่จะพูดได้ไหมvar sortedObjs = _.sortBy( objs, 'first_nom' );. objsจะไม่ถูกจัดเรียงตัวเองเป็นผลมาจากนี้ ฟังก์ชั่นจะส่งกลับอาร์เรย์ที่เรียงลำดับ นั่นจะทำให้ชัดเจนยิ่งขึ้น
Jess

10
ในการย้อนกลับการเรียงลำดับ:var reverseSortedObjs = _.sortBy( objs, 'first_nom' ).reverse();
Erdal G.

2
คุณต้องโหลด javascript libary "underscore":<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"> </script>
and-bri

5
นอกจากนี้ยังมีให้Lodashสำหรับผู้ที่ต้องการหนึ่ง
WoJ

2
ใน lodash นี้จะเหมือนกัน: var sortedObjs = _.sortBy( objs, 'first_nom' );หรือหากคุณต้องการในลำดับที่แตกต่างกัน:var sortedObjs = _.orderBy( objs, ['first_nom'],['dsc'] );
Travis Heeter

186

อย่าเข้าใจว่าทำไมคนถึงทำให้มันซับซ้อน:

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

สำหรับเครื่องยนต์ที่เข้มงวด:

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

สลับโอเปอเรเตอร์เพื่อให้เรียงลำดับตามลำดับตัวอักษรแบบย้อนกลับ


17
สิ่งนี้ไม่ถูกต้องเนื่องจากฟังก์ชันที่ใช้ในการเรียงควรส่งคืน -1, 0 หรือ 1 แต่ฟังก์ชันด้านบนจะส่งคืนบูลีน การเรียงลำดับทำงานได้ดีในโครเมี่ยม แต่ล้มเหลวใน PhantomJS เป็นต้น ดูcode.google.com/p/phantomjs/issues/detail?id=1090
schup

เอ็นจิ้นบางตัวเกี่ยวกับความโง่เขลาวิธีนี้เป็นการใช้ประโยชน์จากสิ่งนั้น ฉันได้อัปเดตคำตอบด้วยรุ่นที่เหมาะสม
p3lim

19
ฉันขอแนะนำให้แก้ไขเพื่อนำออกเวอร์ชันแรก มันกระชับมากขึ้นดังนั้นดูน่าดึงดูดยิ่งขึ้น แต่ก็ใช้งานไม่ได้อย่างน้อยก็ไม่น่าเชื่อถือ หากมีคนลองใช้งานในเบราว์เซอร์เดียวและใช้งานได้พวกเขาอาจไม่รู้ตัวว่ามีปัญหา (โดยเฉพาะถ้าพวกเขาไม่ได้อ่านความคิดเห็น) รุ่นที่สองทำงานได้อย่างถูกต้องดังนั้นจึงไม่จำเป็นสำหรับรุ่นแรก
Kate

2
@ Simon ฉันชื่นชมการมีรุ่น "ผิดเล็กน้อย" เป็นอันดับแรกเนื่องจากการใช้งานที่เข้มงวดใช้เวลาสองสามวินาทีในการวิเคราะห์และทำความเข้าใจและจะยากกว่านี้หากไม่มี
แอรอนเชอร์แมน

1
@ Lion789 ทำเช่นนี้:if(a.count == b.count) return a.name > b.name; else return a.count > b.count;
p3lim

62

หากคุณมีนามสกุลที่ซ้ำกันคุณอาจเรียงลำดับตามชื่อ -

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

@Bad FeelingAbout สิ่งนี้จะคืนค่า -1 หรือ 1 หมายความว่าอย่างไร ฉันเข้าใจว่า -1 หมายถึงว่า A น้อยกว่า B เพียงแค่ใช้ไวยากรณ์ แต่ทำไมต้องใช้ 1 หรือ -1 ฉันเห็นว่าทุกคนใช้ตัวเลขเหล่านั้นเป็นค่าตอบแทน แต่ทำไม ขอบคุณ
Chris22

1
@ Chris22 จำนวนลบส่งคืนหมายความว่าbควรมาหลังจากaในอาร์เรย์ ถ้าเป็นจำนวนบวกจะถูกส่งกลับก็หมายความว่าควรจะมาหลังจากa bหาก0ถูกส่งคืนหมายความว่าพวกเขาถือว่าเท่ากัน คุณสามารถอ่านเอกสารประกอบได้เสมอ: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
......

@Bad FeelingAbout ขอบคุณมากสำหรับคำอธิบายและลิงค์ เชื่อหรือไม่ว่าฉันทำโค้ดตัวอย่างหลายชุดโดยใช้1, 0, -1ก่อนที่ฉันจะถามสิ่งนี้ ฉันไม่ได้หาข้อมูลที่ฉันต้องการ
Chris22

48

วิธีที่ง่ายและรวดเร็วในการแก้ไขปัญหานี้โดยใช้การสืบทอดต้นแบบ:

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

ตัวอย่าง / การใช้งาน

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"}]

อัปเดต:ไม่แก้ไขอาเรย์ดั้งเดิมอีกต่อไป


5
มันไม่ใช่แค่ส่งคืนอาเรย์อีกตัว แต่จริง ๆ แล้วเรียงลำดับเดิม!
Vinay Aggarwal

หากคุณต้องการให้แน่ใจว่าคุณกำลังใช้การเรียงแบบเป็นธรรมชาติกับตัวเลข (เช่น 0,1,2,10,11 ฯลฯ ... ) ให้ใช้การแยกวิเคราะห์ด้วยชุด Radix developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ...... ดังนั้น: return (parseInt (a [p], 10)> parseInt (b [p], 10))? 1: (parseInt (a [p], 10) <parseInt (b [p], 10))? -1: 0;
พอล

@codehuntr ขอบคุณสำหรับการแก้ไข แต่ฉันเดาว่าแทนที่จะทำให้ฟังก์ชั่นการเรียงลำดับเพื่อทำเรื่องนี้มันจะดีกว่าถ้าเราสร้างฟังก์ชั่นแยกต่างหากเพื่อแก้ไขชนิดข้อมูล เพราะฟังก์ชั่นการเรียงลำดับไม่สามารถบอกได้ว่าคุณสมบัติใดจะมีข้อมูลประเภทใด :)
Vinay Aggarwal

ดีมาก. สลับลูกศรเพื่อรับผลลัพท์ขึ้น / ลง
Abdul Sadik Yalcin

4
ไม่เคยแนะนำวิธีแก้ปัญหาที่ดัดแปลงต้นแบบของวัตถุหลัก
pbanka

39

ตั้งแต่ปีพ. ศ. 2561 มีวิธีแก้ปัญหาที่สั้นกว่าและสวยงามมาก เพียงแค่ใช้ Array.prototype.sort ()

ตัวอย่าง:

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
ในสตริงคำถามที่ใช้สำหรับการเปรียบเทียบเมื่อเทียบกับตัวเลข คำตอบของคุณใช้งานได้ดีในการเรียงลำดับตัวเลข แต่ไม่ดีสำหรับการเปรียบเทียบตามสตริง
smcstewart

a.value - b.valueใช้ในการเปรียบเทียบคุณลักษณะของวัตถุ ( ตัวเลขในกรณีนี้) สามารถนำมาใช้สำหรับหลาย ๆ ครั้งของข้อมูล ยกตัวอย่างเช่น regex สามารถนำมาใช้เพื่อเปรียบเทียบคู่ของเพื่อนบ้านแต่ละสาย
0leg

1
@ 0leg ฉันต้องการดูตัวอย่างของการใช้ regex เพื่อเปรียบเทียบสตริงด้วยวิธีนี้
Bob Stein

การใช้งานนี้ค่อนข้างดีหากคุณต้องการจัดเรียงตาม ID ใช่คุณได้แนะนำให้ใช้ regex เพื่อเปรียบเทียบสตริงที่อยู่ใกล้เคียงซึ่งทำให้การแก้ปัญหามีความซับซ้อนมากขึ้นในขณะที่จุดประสงค์ของรุ่น simpliefied นี้จะเป็นอย่างอื่นถ้าใช้ regex พร้อมกับวิธีการแก้ปัญหาที่กำหนด ความเรียบง่ายเป็นสิ่งที่ดีที่สุด
surendrapanday

33

คำตอบเก่าที่ไม่ถูกต้อง:

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

UPDATE

จากความคิดเห็นของ Beauchamp:

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

รูปแบบที่อ่านได้มากขึ้น:

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

ไม่ประกอบไปด้วยสามส่วน:

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

คำอธิบาย: Number()จะเหวี่ยงtrueไป1และจะfalse0


ใช้งานได้ แต่ผลลัพธ์ไม่แน่นอนด้วยเหตุผลบางอย่าง
TitanFighter

@ AO17 ไม่มันจะไม่ คุณไม่สามารถลบสตริงได้
Patrick Roberts

15
สิ่งนี้ควรทำ:arr.sort((a, b) => a.name < b.name ? -1 : (a.name > b.name ? 1 : 0))
Jean-François Beauchamp

3
@ Jean-FrançoisBeauchampโซลูชันของคุณทำงานได้อย่างสมบูรณ์แบบและดีขึ้นมาก
Ahsan

อันดับที่ 3 พร้อม Number นั้นตรงไปตรงมาและดี!
Kojo

29

แทนที่จะใช้ฟังก์ชันการเปรียบเทียบแบบกำหนดเองคุณสามารถสร้างประเภทวัตถุด้วยtoString()วิธีการแบบกำหนดเอง(ซึ่งถูกเรียกใช้โดยฟังก์ชันการเปรียบเทียบค่าเริ่มต้น):

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 (superset of Underscore.js )

เป็นการดีที่จะไม่เพิ่มกรอบการทำงานสำหรับทุก ๆ ส่วนของตรรกะ แต่การใช้เฟรมเวิร์กยูทิลิตี้ที่ผ่านการทดสอบอย่างดีสามารถเพิ่มความเร็วในการพัฒนาและลดจำนวนข้อบกพร่อง

Lodash สร้างโค้ดที่สะอาดมากและส่งเสริมรูปแบบการเขียนโปรแกรมที่ใช้งานได้มากกว่า ในแวบเดียวมันจะชัดเจนว่าเจตนาของรหัสคืออะไร

ปัญหาของ OP สามารถแก้ไขได้อย่างง่ายๆดังนี้:

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

ข้อมูลเพิ่มเติม? เช่นเรามีวัตถุที่ซ้อนกันดังต่อไปนี้:

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

ตอนนี้เราสามารถใช้_.property shorthand user.ageเพื่อระบุพา ธ ไปยังคุณสมบัติที่ควรจับคู่ เราจะจัดเรียงวัตถุผู้ใช้ตามคุณสมบัติอายุที่ซ้อนกัน ใช่มันช่วยให้การจับคู่คุณสมบัติซ้อนกัน!

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

ต้องการกลับรายการไหม ไม่มีปัญหา. ใช้_.reverse

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

ต้องการรวมทั้งสองอย่างโดยใช้โซ่ ?

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

หรือเมื่อไหร่ที่คุณชอบไหลผ่านโซ่

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

28

คุณสามารถใช้ได้

วิธีที่ง่ายที่สุด: Lodash

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

วิธีการนี้มีลักษณะเหมือน _.sortBy ยกเว้นว่าจะอนุญาตให้ระบุลำดับการเรียงของ iterate ที่จะเรียงลำดับ หากไม่มีการระบุคำสั่งซื้อค่าทั้งหมดจะเรียงลำดับจากน้อยไปหามาก มิฉะนั้นให้ระบุคำสั่ง "desc" สำหรับการเรียงจากมากไปน้อยหรือ "asc" สำหรับการเรียงลำดับจากน้อยไปมากของค่าที่เกี่ยวข้อง

ข้อโต้แย้ง

การเก็บ (Array | Object): การรวบรวมซ้ำ [iteratees = [_. identity]] (Array [] | Function [] | Object [] | string []): iterate เพื่อเรียงลำดับ [orders] (string []): ลำดับการเรียงของ iterate

ผลตอบแทน

(อาร์เรย์): ส่งคืนอาร์เรย์ที่เรียงลำดับใหม่


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

มีคำตอบที่ดีมากมายที่นี่ แต่ฉันอยากจะชี้ให้เห็นว่าพวกเขาสามารถขยายได้ง่าย ๆ เพื่อให้ได้การจัดเรียงที่ซับซ้อนมากขึ้น สิ่งเดียวที่คุณต้องทำคือใช้ตัวดำเนินการ OR เพื่อเปรียบเทียบฟังก์ชันลูกโซ่เช่นนี้:

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

ที่ไหนfn1, fn2... มีฟังก์ชั่นการจัดเรียงที่ผลตอบแทน [-1,0,1] ผลลัพธ์นี้ใน "sorting by fn1", "sorting by fn2" ซึ่งค่อนข้างจะเท่ากับ ORDER BY ใน SQL

การแก้ปัญหานี้จะขึ้นอยู่กับลักษณะการทำงานของ||ผู้ประกอบการซึ่งจะประเมินกับการแสดงออกครั้งแรกที่ได้รับการประเมินที่สามารถแปลงเป็นจริง

แบบฟอร์มที่ง่ายที่สุดมีฟังก์ชันอินไลน์เพียงฟังก์ชันเดียวดังนี้:

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

มีสองขั้นตอน last_nomในการfirst_nomเรียงลำดับจะเป็นดังนี้:

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

ฟังก์ชันการเปรียบเทียบทั่วไปอาจเป็นดังนี้:

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

ฟังก์ชั่นนี้สามารถขยายเพื่อรองรับฟิลด์ตัวเลข, ความไวของเคส, ประเภทข้อมูลทางโบราณคดีเป็นต้น

คุณสามารถใช้มันเพื่อผูกมัดพวกเขาโดยเรียงลำดับความสำคัญ:

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

จุดที่นี่คือ JavaScript ที่บริสุทธิ์ด้วยวิธีการทำงานสามารถนำคุณไปได้ไกลโดยไม่ต้องใช้ไลบรารีภายนอกหรือรหัสที่ซับซ้อน นอกจากนี้ยังมีประสิทธิภาพมากเนื่องจากไม่มีการแยกสตริงที่ต้องทำ


23

ตัวอย่างการใช้งาน:

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

สคริปต์:

/**
 * @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;
  };
};

ขอขอบคุณที่ทำลายสิ่งนี้ฉันพยายามทำความเข้าใจว่าเพราะเหตุใดจึงใช้ตัวเลข1, 0, -1เพื่อจัดเรียงลำดับ แม้จะมีคำอธิบายของคุณข้างต้นซึ่งดูดีมาก - ฉันยังไม่ค่อยเข้าใจ ฉันมักจะคิดว่า-1เมื่อใช้คุณสมบัติความยาวของอาร์เรย์เช่น: arr.length = -1หมายความว่าไม่พบรายการ ฉันอาจผสมปนกันที่นี่ แต่คุณช่วยฉันเข้าใจว่าทำไมใช้ตัวเลข1, 0, -1เพื่อกำหนดลำดับ ขอบคุณ
Chris22

1
สิ่งนี้ไม่ถูกต้องทั้งหมดแต่อาจช่วยให้คิดได้ดังนี้: ฟังก์ชันที่ส่งไปยัง array.sort ถูกเรียกหนึ่งครั้งสำหรับแต่ละรายการในอาร์เรย์เนื่องจากอาร์กิวเมนต์ชื่อ "a" ค่าที่ส่งคืนของการเรียกใช้ฟังก์ชันแต่ละครั้งคือวิธีที่ดัชนี (หมายเลขตำแหน่งปัจจุบัน) ของรายการ "a" ควรเปลี่ยนแปลงเมื่อเปรียบเทียบกับรายการถัดไป "b" ดัชนีกำหนดลำดับของอาร์เรย์ (0, 1, 2 ฯลฯ ) ดังนั้นถ้า "a" อยู่ที่ดัชนี 5 และคุณกลับ -1 แล้ว 5 + -1 == 4 (เลื่อนไปไว้ด้านหน้าใกล้) 5 + 0 == 5 (เก็บไว้ในตำแหน่งที่มันอยู่) ฯลฯ มันจะเดินอาร์เรย์เปรียบเทียบ 2 เพื่อนบ้านในแต่ละครั้งจนกว่าจะถึงจุดสิ้นสุด
เจมี่เมสัน

ขอบคุณที่สละเวลาอธิบายเพิ่มเติม ดังนั้นโดยใช้คำอธิบายของคุณและMDN Array.prototype.sortฉันจะบอกคุณว่าฉันคิดยังไง: เปรียบเทียบกับaและbถ้าaมากกว่าb1 บวกกับดัชนีของaและวางไว้ข้างหลังbถ้าaน้อยกว่าbลบจาก 1 และวางไว้ในด้านหน้าของa bถ้าaและbเหมือนกันให้เพิ่ม 0 aและปล่อยให้มันอยู่ในที่
Chris22

22

ฉันไม่ได้เห็นวิธีการเฉพาะที่แนะนำดังนั้นนี่เป็นวิธีเปรียบเทียบโดยสังเขปที่ฉันชอบที่จะใช้กับทั้งสองstringและ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));

นี่คือคำอธิบายของsortBy():

sortBy()ยอมรับว่าเลือกสิ่งที่มีค่าจากวัตถุที่จะใช้การเปรียบเทียบและผลตอบแทนฟังก์ชั่นที่สามารถส่งโดยตรงไปยังfn Array.prototype.sort()ในตัวอย่างนี้เราใช้o.last_nomเป็นค่าสำหรับการเปรียบเทียบดังนั้นเมื่อใดก็ตามที่เราได้รับวัตถุสองArray.prototype.sort()อย่างเช่น

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

และ

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

เราใช้

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

เพื่อเปรียบเทียบพวกเขา

จำได้ว่าfn = o => o.last_nomเราสามารถขยายฟังก์ชั่นการเปรียบเทียบให้เทียบเท่า

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

ตัวดำเนินการเชิงตรรกะ OR ||มีฟังก์ชันการลัดวงจรที่มีประโยชน์มากที่นี่ เนื่องจากวิธีการทำงานร่างกายของฟังก์ชันข้างต้นจึงมีความหมาย

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

ในฐานะโบนัสเพิ่มเติมนี่เทียบเท่า ECMAScript 5 โดยไม่มีฟังก์ชั่นลูกศรซึ่งน่าเสียดายยิ่งกว่า:

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

ฉันรู้ว่าคำถามนี้เก่าเกินไป แต่ฉันไม่เห็นการใช้งานที่คล้ายกับของฉัน
รุ่นนี้จะขึ้นอยู่กับSchwartzian เปลี่ยนสำนวน

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

นี่คือตัวอย่างวิธีการใช้งาน:

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

เรียงลำดับ (เพิ่มเติม) อาร์เรย์ที่ซับซ้อนของวัตถุ

เนื่องจากคุณอาจพบโครงสร้างข้อมูลที่ซับซ้อนมากขึ้นเช่นอาเรย์นี้ฉันจะขยายการแก้ปัญหา

TL; DR

จะรุ่น pluggable มากขึ้นบนพื้นฐาน@ ege-Özcan 's น่ารักมากคำตอบ

ปัญหา

ฉันพบด้านล่างและไม่สามารถเปลี่ยนแปลงได้ ฉันยังไม่ต้องการที่จะแบนวัตถุชั่วคราว ฉันไม่ต้องการใช้ขีดเส้นใต้ / lodash ส่วนใหญ่ด้วยเหตุผลด้านประสิทธิภาพและความสนุกในการใช้งานด้วยตนเอง

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

เป้าหมาย

เป้าหมายคือการจัดเรียงเป็นหลักโดยPeople.Name.nameและครั้งที่สองโดยPeople.Name.surname

อุปสรรค

ขณะนี้ในโซลูชันพื้นฐานใช้เครื่องหมายวงเล็บเพื่อคำนวณคุณสมบัติเพื่อจัดเรียงแบบไดนามิก อย่างไรก็ตามที่นี่เราจะต้องสร้างเครื่องหมายวงเล็บแบบไดนามิกด้วยเนื่องจากคุณคาดหวังว่าบางอย่างPeople['Name.name']จะทำงาน - ซึ่งไม่ได้

เพียงแค่ทำPeople['Name']['name']ในมืออื่น ๆ ที่เป็นแบบคงที่และมีเพียงช่วยให้คุณไปลงnระดับ -th

สารละลาย

การเพิ่มหลักที่นี่จะเป็นการเดินแผนผังต้นไม้และกำหนดค่าของใบไม้สุดท้ายที่คุณต้องระบุเช่นเดียวกับใบไม้ตัวกลางใด ๆ

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

ตัวอย่าง

ตัวอย่างการทำงานกับ JSBin


2
ทำไม? นี่ไม่ใช่คำตอบสำหรับคำถามดั้งเดิมและ "เป้าหมาย" สามารถแก้ไขได้อย่างง่ายดายด้วย People.sort ((a, b) => {return a.Name.name.localeCompare (b.Name.name) || a.Name .surname.localeCompare (b.Name.surname)})
Tero Tolonen

12

อีกหนึ่งตัวเลือก:

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

เรียงลำดับจากน้อยไปมากตามค่าเริ่มต้น


1
รุ่นที่มีการเปลี่ยนแปลงเล็กน้อยสำหรับการเรียงลำดับตามหลายฟิลด์อยู่ที่นี่หากจำเป็น: stackoverflow.com/questions/6913512/…
Ravshan Samandarov

ดูเหมือนว่ามันอาจจะเป็นหนึ่งในถัดไป: ฟังก์ชั่นการส่งออก generateSortFn (prop: สตริง, ย้อนกลับ: boolean = false): (... args: any) => จำนวน {กลับ (a, b) => {กลับมา [prop ] <b [prop]? กลับด้าน 1: -1: a [prop]> b [prop]? กลับด้าน -1: 1: 0; }; }
Den Kerny

ฉันต้องการโค้ดที่อ่านได้มากกว่าโค้ดที่สั้นที่สุด
Ravshan Samandarov

เห็นด้วย แต่ในบางกรณีฉันไม่ต้องการดูฟังก์ชันยูทิลิตี้
Den Kerny

11

ฟังก์ชั่นง่าย ๆ ที่เรียงลำดับอาร์เรย์ของวัตถุตามคุณสมบัติ

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
}

การใช้งาน:

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

โซลูชันนี้ทำงานอย่างสมบูรณ์แบบสำหรับฉันในการจัดเรียงแบบสองทิศทาง ขอบคุณนะ
manjuvreddy

10

วิธีง่ายๆ:

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

ดูว่า'.toLowerCase()'มีความจำเป็นเพื่อป้องกันความผิดพลาดในการเปรียบเทียบสตริง


4
คุณสามารถใช้ฟังก์ชั่นลูกศรเพื่อให้โค้ดดูสง่างามขึ้นอีกนิด:objs.sort( (a,b) => b.last_nom.toLowerCase() < a.last_nom.toLowerCase() );
Sertage

นี้เป็นธรรมด้วยเหตุผลเดียวกันตามที่อธิบายไว้ที่นี่
Patrick Roberts

2
ฟังก์ชั่นลูกศรไม่เหมาะกับ ES5 ตันของเครื่องยนต์ยังคง จำกัด อยู่ที่ ES5 ในกรณีของฉันฉันพบคำตอบข้างต้นอย่างมีนัยสำคัญที่ดีขึ้นเพราะฉันอยู่ในเครื่องยนต์ ES5 (บังคับโดย บริษัท ของฉัน)
dylanh724

9

param เพิ่มเติมสำหรับรหัสEge Özcan

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 ที่มีพลวัตเข้ากับแนวคิดของ Vinay คุณจะได้รับโซลูชั่นที่มีประสิทธิภาพที่ดี:

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

การใช้งาน:

// 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
ขอบคุณสำหรับความคิด! โดยวิธีการโปรดอย่าส่งเสริมให้ผู้คนเปลี่ยนต้นแบบ Array (ดูคำเตือนในตอนท้ายของตัวอย่างของฉัน)
Ege Özcan

8

จากตัวอย่างของคุณคุณต้องเรียงลำดับตามสองฟิลด์ (นามสกุล, ชื่อจริง), แทนที่จะเป็นหนึ่งฟิลด์ คุณสามารถใช้ไลบรารีAlasqlเพื่อจัดเรียงนี้ในหนึ่งบรรทัด:

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

ลองตัวอย่างนี้ที่ jsFiddle


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

1
จริงๆแล้วมันดูเหมือนจะไม่ทำงานต้องใช้คำตอบที่ยอมรับได้ การเรียงลำดับไม่ถูกต้อง
madprops

8

รับตัวอย่างดั้งเดิม:

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

จัดเรียงตามหลายฟิลด์:

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

หมายเหตุ

  • a.localeCompare(b)จะได้รับการสนับสนุนในระดับสากลและผลตอบแทน -1,0,1 ถ้าa<b, a==b, a>bตามลำดับ
  • ||ในบรรทัดสุดท้ายให้มากกว่าความสำคัญlast_nomfirst_nom
  • การลบจะทำงานบนฟิลด์ตัวเลข: var age_order = left.age - right.age;
  • ปฏิเสธที่จะกลับคำสั่ง return -last_nom_order || -first_nom_order || -age_order;

8

ลองนี้

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

ทางออกที่ดีที่สุดและง่าย
Omar Hasan

7

คุณอาจต้องแปลงเป็นตัวพิมพ์เล็กเพื่อป้องกันความสับสน

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
โปรดพิจารณาการแก้ไขโพสต์ของคุณเพื่อเพิ่มคำอธิบายเพิ่มเติมเกี่ยวกับสิ่งที่รหัสของคุณทำและเหตุผลที่จะแก้ไขปัญหา คำตอบที่ส่วนใหญ่มีรหัส (แม้ว่าจะใช้งานได้) มักจะไม่ช่วยให้ OP เข้าใจปัญหาของพวกเขา
Drenmi

7

ใช้ Ramda

npm ติดตั้ง 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

นี่เป็นปัญหาง่าย ๆ ไม่รู้ว่าทำไมผู้คนถึงมีวิธีแก้ปัญหาที่ซับซ้อนเช่นนี้
ฟังก์ชั่นการจัดเรียงง่าย (ขึ้นอยู่กับอัลกอริทึมการเรียงลำดับอย่างรวดเร็ว ):

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

ใช้ตัวอย่าง:

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

5
การใช้การจัดเรียงอย่างรวดเร็วใน js เป็นวิธีง่ายๆอย่างไร อัลกอริทึมง่าย ๆ แต่ไม่ใช่วิธีแก้ปัญหาง่าย ๆ
แอนดรู

ง่ายเนื่องจากไม่ใช้ไลบรารีภายนอกและไม่เปลี่ยนต้นแบบของวัตถุ ในความคิดของฉันความยาวของรหัสไม่ส่งผลกระทบโดยตรงต่อความซับซ้อนของรหัส
Gil Epshtain

2
ผมขอลองด้วยคำพูดที่ต่างกัน: การสร้างล้อใหม่เป็นวิธีแก้ปัญหาง่ายๆได้อย่างไร?
Roberto14
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.