จะทำการเรียงลำดับตัวพิมพ์เล็กและใหญ่ใน JavaScript ได้อย่างไร?


220

ฉันมีชุดของสตริงที่ฉันต้องการเรียงลำดับในจาวาสคริปต์ แต่ในกรณีที่ไม่คำนึงถึงขนาดตัวพิมพ์ วิธีการทำสิ่งนี้?

คำตอบ:


404

ใน (เกือบ :) หนึ่งซับ

["Foo", "bar"].sort(function (a, b) {
    return a.toLowerCase().localeCompare(b.toLowerCase());
});

ซึ่งส่งผลให้

[ 'bar', 'Foo' ]

ในขณะที่

["Foo", "bar"].sort();

ผลลัพธ์ใน

[ 'Foo', 'bar' ]

9
โปรดทราบว่าตัวเลือกขั้นสูงของ localeCompare ยังไม่รองรับในทุกแพลตฟอร์ม / เบราว์เซอร์ ฉันรู้ว่ามันไม่ได้ใช้ในตัวอย่างนี้ แต่ต้องการเพิ่มเพื่อความชัดเจน ดู MDN สำหรับข้อมูลเพิ่มเติม
Ayame__

97
หากคุณกำลังจะเกี่ยวข้องกับ localeCompare () คุณสามารถใช้ความสามารถของตัวพิมพ์เล็กและตัวพิมพ์เล็กเช่น:return a.localeCompare(b, 'en', {'sensitivity': 'base'});
Michael Dyck

2
+1 สำหรับการไม่โทรtoLowerCase()เมื่อlocaleCompareทำได้โดยค่าเริ่มต้นในบางกรณี คุณสามารถอ่านเพิ่มเติมเกี่ยวกับพารามิเตอร์ที่จะส่งผ่านได้ที่นี่: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Milimetric

3
@Milimetric สอดคล้องกับหน้าที่อ้างอิงคุณลักษณะนั้นไม่รองรับเบราว์เซอร์บางตัว (เช่น IE <11 หรือ Safari) โซลูชันที่กล่าวถึงในที่นี้ดีมาก แต่ก็ยังต้องการ backporting / polyfill สำหรับเบราว์เซอร์บางตัว
3k-

2
หากคุณมีอาร์เรย์ขนาดใหญ่มันเหมาะสมที่จะใช้items.sort(new Intl.Collator('en').compare)เพื่อประสิทธิภาพที่ดีขึ้น (ดูMDN .)
valtlai

60
myArray.sort(
  function(a, b) {
    if (a.toLowerCase() < b.toLowerCase()) return -1;
    if (a.toLowerCase() > b.toLowerCase()) return 1;
    return 0;
  }
);

แก้ไข: โปรดทราบว่าฉันเดิมเขียนสิ่งนี้เพื่อแสดงเทคนิคแทนที่จะมีประสิทธิภาพในใจ โปรดอ้างอิงคำตอบ @Ivan Krechetov สำหรับโซลูชันที่กะทัดรัดยิ่งขึ้น


3
สิ่งนี้สามารถเรียกtoLowerCaseสองครั้งในแต่ละสตริง จะมีประสิทธิภาพมากกว่าในการจัดเก็บสตริงที่ลดลงในตัวแปร
จาค็อบ

จริงและขอบคุณ ฉันเขียนสิ่งนี้ด้วยความชัดเจนในใจไม่ใช่ประสิทธิภาพ ฉันคิดว่าฉันควรทราบว่า
Ron tornambe

1
@Jacob เพื่อความยุติธรรมคำตอบที่ยอมรับมีปัญหาพื้นฐานเหมือนกัน: อาจเป็นไปได้ที่จะเรียก.toLowerCase()หลายครั้งสำหรับแต่ละรายการในอาร์เรย์ ตัวอย่างเช่น 45 การเรียกไปยังฟังก์ชันการเปรียบเทียบเมื่อเรียงลำดับ 10 รายการในลำดับย้อนกลับ var i = 0; ["z","y","x","w","v","u","t","s","r","q"].sort(function (a, b) {++i; return a.toLowerCase().localeCompare(b.toLowerCase());}); console.log("Calls to Compare: " + i); // i === 45
nothingisnecessary

47

ถึงเวลาทบทวนคำถามเก่านี้อีกครั้ง

toLowerCaseคุณไม่ควรใช้โซลูชั่นอาศัย พวกเขาไม่มีประสิทธิภาพและไม่สามารถใช้งานได้ในบางภาษา (เช่นภาษาตุรกี) ชอบสิ่งนี้:

['Foo', 'bar'].sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))

ตรวจสอบเอกสารเกี่ยวกับความเข้ากันได้ของเบราว์เซอร์และสิ่งที่ต้องรู้เกี่ยวกับsensitivityตัวเลือก


1
ระวังสิ่งนี้ไม่ได้รับการสนับสนุนในเครื่องมือจาวาสคริปต์ทั้งหมด
Lubos Turek

26
arr.sort(function(a,b) {
    a = a.toLowerCase();
    b = b.toLowerCase();
    if (a == b) return 0;
    if (a > b) return 1;
    return -1;
});

1
หรือreturn a === b ? 0 : a > b ? 1 : -1;
Devin G Rhode

สิ่งนี้จะไม่ทำงานตามที่คาดไว้สำหรับสตริงที่แสดงตัวเลข ตัวดำเนินการทางคณิตศาสตร์จะใช้ซีแมนทิกส์ของตัวเลขแทนสตริง เช่นถ้าเรามี["111", "33"]เราอาจต้องการให้มันกลับมา["111", "33"]เพราะ 1 มาก่อน 3 ในการสั่งรหัสตัวอักษร แต่ฟังก์ชั่นในคำตอบนี้จะกลับมา["33", "111"]เพราะจำนวนน้อยกว่าจำนวน33 111
Austin Davis

@AustinDavis และ"33" > "111" === true 33 > 111 === falseมันทำงานได้ตามที่ตั้งใจไว้
Niet the Dark Absolute

12

นอกจากนี้คุณยังสามารถใช้Intl.Collator().compareMDN ใหม่ได้อย่างมีประสิทธิภาพเมื่อเรียงลำดับอาร์เรย์ ข้อเสียคือเบราว์เซอร์รุ่นเก่าไม่รองรับ MDN ระบุว่าไม่รองรับเลยใน Safari จำเป็นต้องตรวจสอบเนื่องจากระบุว่าIntl.Collatorรองรับ

เมื่อเปรียบเทียบสตริงจำนวนมากเช่นในการจัดเรียงอาร์เรย์ขนาดใหญ่จะเป็นการดีกว่าที่จะสร้างออบเจกต์ Intl.Collator และใช้ฟังก์ชันที่มีให้โดยคุณสมบัติการเปรียบเทียบ

["Foo", "bar"].sort(Intl.Collator().compare); //["bar", "Foo"]

11

หากคุณต้องการรับประกันคำสั่งเดียวกันโดยไม่คำนึงถึงลำดับขององค์ประกอบในอาร์เรย์อินพุตนี่คือการเรียงลำดับที่เสถียร :

myArray.sort(function(a, b) {
    /* Storing case insensitive comparison */
    var comparison = a.toLowerCase().localeCompare(b.toLowerCase());
    /* If strings are equal in case insensitive comparison */
    if (comparison === 0) {
        /* Return case sensitive comparison instead */
        return a.localeCompare(b);
    }
    /* Otherwise return result */
    return comparison;
});

5

ปกติในกรณีที่มี.sort().toLowerCase()


4

คุณยังสามารถใช้ตัวดำเนินการ Elvis:

arr = ['Bob', 'charley', 'fudge', 'Fudge', 'biscuit'];
arr.sort(function(s1, s2){
    var l=s1.toLowerCase(), m=s2.toLowerCase();
    return l===m?0:l>m?1:-1;
});
console.log(arr);

ให้:

biscuit,Bob,charley,fudge,Fudge

วิธี localeCompare น่าจะดีแม้ว่า ...

หมายเหตุ: ตัวดำเนินการ Elvis เป็นรูปแบบสั้น ๆ ว่า 'ผู้ประกอบการที่ประกอบไปด้วยสามส่วน' หากเป็นเช่นนั้นโดยทั่วไปจะมีการมอบหมาย
หากคุณมองไปที่?: ด้านข้างดูเหมือนว่า Elvis ...
เช่นแทนที่จะเป็น:

if (y) {
  x = 1;
} else {
  x = 2;
}

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

x = y?1:2;

เช่นเมื่อ y เป็นจริงแล้วส่งคืน 1 (สำหรับการมอบหมายให้ x) มิฉะนั้นคืน 2 (สำหรับการมอบหมายให้ x)


5
เพื่อให้เป็นคนคล่องแคล่วนี่ไม่ใช่ตัวดำเนินการของ Elvis นี่เป็นเพียงผู้ประกอบการที่ประกอบไปด้วยพื้นฐาน ผู้ประกอบการเอลวิสที่แท้จริงเป็นโมฆะ-coalescing เช่นแทนที่จะคุณสามารถทำได้x = y ? y : z x = y ?: zJavascript ไม่มีโอเปอเรเตอร์ Elvis จริงๆ แต่คุณสามารถใช้x = y || zในลักษณะเดียวกันได้
Charles Wood

3

คำตอบอื่น ๆ สมมติว่าอาร์เรย์มีสตริง วิธีการของฉันจะดีกว่าเพราะมันจะทำงานแม้ว่าอาร์เรย์มีโมฆะไม่ได้กำหนดหรืออื่น ๆ ที่ไม่ใช่สตริง

var notdefined;
var myarray = ['a', 'c', null, notdefined, 'nulk', 'BYE', 'nulm'];

myarray.sort(ignoreCase);

alert(JSON.stringify(myarray));    // show the result

function ignoreCase(a,b) {
    return (''+a).toUpperCase() < (''+b).toUpperCase() ? -1 : 1;
}

nullจะถูกจัดเรียงระหว่าง nulk 'และ 'nulm' แต่undefinedจะได้รับการเสมอเรียงสุดท้าย


(''+notdefined) === "undefined"มันจะเรียงลำดับก่อน "z"
MattW

ฉันคิดว่าฉันควรค้นหาคำจำกัดความของArray.prototype.sort: | เพราะส่วนที่เกี่ยวกับ(''+notdefined) === "undefined" เป็นจริง ... ซึ่งหมายความว่าถ้าคุณพลิก -1 และ 1 ในฟังก์ชั่นการเรียงลำดับเพื่อกลับคำสั่งซื้อที่ไม่ได้กำหนดยังคงเรียงลำดับไปยังจุดสิ้นสุด นอกจากนี้ยังจำเป็นต้องได้รับการพิจารณาเมื่อใช้ฟังก์ชันการเปรียบเทียบนอกบริบทของการเรียงลำดับอาร์เรย์ (เช่นเดียวกับเมื่อฉันมาถึงคำถามนี้)
MattW

และในขณะนี้ได้ไตร่ตรองArray.prototype.sortนิยามนั้น- เพิ่มความคิดเห็นให้มากขึ้น ก่อนอื่นไม่จำเป็นต้องใช้(''+a)- ECMAScript toString()จะต้องเรียกใช้องค์ประกอบก่อนที่จะส่งไปยัง comparFn ประการที่สองความจริงที่ว่าignoreCaseผลตอบแทน1เมื่อเปรียบเทียบสตริงที่เท่ากัน (รวมเท่ากัน แต่สำหรับกรณี) หมายความว่าข้อมูลจำเพาะไม่ได้กำหนดผลลัพธ์หากมีค่าที่ซ้ำกัน
MattW

@MattW มันดูเหมือนว่าฉันว่าundefinedเป็นกรณีพิเศษซึ่งสำหรับใด ๆ x x <ไม่ได้กำหนดและ x> ไม่ได้กำหนดมีทั้งที่เป็นเท็จ นั่นundefinedเป็นครั้งสุดท้ายเสมอเป็นผลพลอยได้จากการดำเนินการเรียงลำดับของการเรียงลำดับ ฉันพยายามเปลี่ยน ('' + a) เป็นเพียง a แต่มันล้มเหลว TypeError: a.toUpperCase is not a functionฉันจะได้รับ เห็นได้ชัดว่าไม่ได้toStringถูกเรียกก่อนการเปรียบเทียบ comparFn
John Henckel

1
อาตกลงว่าเหมาะสมแล้ว สำหรับundefinedการเปรียบเทียบไม่เคยเรียกว่า
John Henckel


1

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

myArray.sort(
  function(a, b) {
    if (a.toLowerCase() < b.toLowerCase()) return -1;
    if (a.toLowerCase() > b.toLowerCase()) return 1;
    return 0;
  }
);

ในการทดลองของฉันฟังก์ชันต่อไปนี้จากคำตอบที่ยอมรับจะเรียงลำดับอย่างถูกต้อง แต่ไม่เปลี่ยนค่า

["Foo", "bar"].sort(function (a, b) {
    return a.toLowerCase().localeCompare(b.toLowerCase());
});

0

สิ่งนี้อาจช่วยได้หากคุณพยายามเข้าใจ:

var array = ["sort", "Me", "alphabetically", "But", "Ignore", "case"];
console.log('Unordered array ---', array, '------------');

array.sort(function(a,b) {
    a = a.toLowerCase();
    b = b.toLowerCase();
    console.log("Compare '" + a + "' and '" + b + "'");

    if( a == b) {
        console.log('Comparison result, 0 --- leave as is ');
        return 0;
    }
    if( a > b) {
        console.log('Comparison result, 1 --- move '+b+' to before '+a+' ');
        return 1;
    }
    console.log('Comparison result, -1 --- move '+a+' to before '+b+' ');
    return -1;


});

console.log('Ordered array ---', array, '------------');


// return logic

/***
If compareFunction(a, b) is less than 0, sort a to a lower index than b, i.e. a comes first.
If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.
If compareFunction(a, b) is greater than 0, sort b to a lower index than a.
***/

http://jsfiddle.net/ianjamieson/wmxn2ram/1/


0
arr.sort(function(a,b) {
    a = a.toLowerCase();
    b = b.toLowerCase();
    if( a == b) return 0;
    if( a > b) return 1;
    return -1;
});

ในฟังก์ชั่นด้านบนถ้าเราเปรียบเทียบเมื่อตัวพิมพ์เล็กสองค่า a และ b เราจะไม่ได้ผลลัพธ์ที่ดี

ตัวอย่างถ้าอาร์เรย์เป็น [A, a, B, c, C, C, D, e, E] และเราใช้ฟังก์ชันข้างต้นเรามีอาร์เรย์นั้น มันไม่เปลี่ยนแปลงอะไรเลย

การมีผลลัพธ์คือ [A, a, B, C, c, D, d, E, e] เราควรเปรียบเทียบอีกครั้งเมื่อค่าตัวพิมพ์เล็กสองตัวเท่ากัน:

function caseInsensitiveComparator(valueA, valueB) {
    var valueALowerCase = valueA.toLowerCase();
    var valueBLowerCase = valueB.toLowerCase();

    if (valueALowerCase < valueBLowerCase) {
        return -1;
    } else if (valueALowerCase > valueBLowerCase) {
        return 1;
    } else { //valueALowerCase === valueBLowerCase
        if (valueA < valueB) {
            return -1;
        } else if (valueA > valueB) {
            return 1;
        } else {
            return 0;
        }
    }
}

-1

ฉันหุ้มคำตอบที่ดีที่สุดไว้ในโพลีฟิลล์เพื่อที่ฉันจะสามารถเรียก. sortIgnoreCase () บนอาเรย์สตริง

// Array.sortIgnoreCase() polyfill
if (!Array.prototype.sortIgnoreCase) {
    Array.prototype.sortIgnoreCase = function () {
        return this.sort(function (a, b) {
            return a.toLowerCase().localeCompare(b.toLowerCase());
        });
    };
}

โปรดอย่าทำเช่นนี้ ดัดแปลงเฉพาะต้นแบบของสิ่งที่คุณเป็นเจ้าของ นี่ไม่ใช่โพลีฟิลเนื่องจากวิธี Array นี้ไม่มีข้อมูลจำเพาะของ ECMAScript
Joe Maffei

-2

/ /iตัดสายของคุณใน นี่เป็นวิธีที่ง่ายในการใช้ regex เพื่อละเว้นการใส่ปลอก


คำถามเกี่ยวกับการเรียงลำดับไม่ตรงกัน
user4642212
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.