Saya memiliki serangkaian string yang harus saya sortir dalam JavaScript, tetapi dengan cara case-insensitive. Bagaimana cara melakukan ini?
Saya memiliki serangkaian string yang harus saya sortir dalam JavaScript, tetapi dengan cara case-insensitive. Bagaimana cara melakukan ini?
Jawaban:
Dalam (hampir :) a-liner
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Yang mengakibatkan
[ 'bar', 'Foo' ]
Sementara
["Foo", "bar"].sort();
hasil dalam
[ 'Foo', 'bar' ]
return a.localeCompare(b, 'en', {'sensitivity': 'base'});
toLowerCase()
ketika localeCompare
sudah melakukannya secara default dalam beberapa kasus. Anda dapat membaca lebih lanjut tentang parameter untuk diteruskan ke sini: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
EDIT: Harap dicatat bahwa saya awalnya menulis ini untuk menggambarkan teknik daripada memiliki kinerja dalam pikiran. Lihat juga jawaban @Ivan Krechetov untuk solusi yang lebih ringkas.
toLowerCase
dua kali pada setiap string; akan lebih efisien untuk menyimpan versi yang lebih rendah dari string dalam variabel.
.toLowerCase()
beberapa kali untuk setiap item dalam array. Misalnya, 45 panggilan ke fungsi bandingkan saat mengurutkan 10 item dalam urutan terbalik. 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
Inilah saatnya untuk meninjau kembali pertanyaan lama ini.
Anda sebaiknya tidak menggunakan solusi yang diandalkan toLowerCase
. Mereka tidak efisien dan tidak berfungsi dalam beberapa bahasa (Turki misalnya). Lebih suka ini:
['Foo', 'bar'].sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))
Periksa dokumentasi untuk kompatibilitas browser dan semua yang perlu diketahui tentang sensitivity
opsi ini.
arr.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
if (a == b) return 0;
if (a > b) return 1;
return -1;
});
return a === b ? 0 : a > b ? 1 : -1;
["111", "33"]
, kita mungkin ingin mengembalikannya ["111", "33"]
karena 1 datang sebelum 3 dalam urutan kode karakter. Namun, fungsi dalam jawaban ini akan kembali ["33", "111"]
karena angkanya 33
kurang dari angkanya 111
.
"33" > "111" === true
dan 33 > 111 === false
. Ini berfungsi sebagaimana dimaksud.
Anda juga dapat menggunakan yang baru Intl.Collator().compare
, per MDN itu lebih efisien saat menyortir array. Kelemahannya adalah tidak didukung oleh peramban lama. MDN menyatakan bahwa itu tidak didukung sama sekali di Safari. Perlu memverifikasinya, karena menyatakan yang Intl.Collator
didukung.
Ketika membandingkan sejumlah besar string, seperti dalam menyortir array besar, lebih baik untuk membuat objek Intl.Collator dan menggunakan fungsi yang disediakan oleh properti pembandingnya.
["Foo", "bar"].sort(Intl.Collator().compare); //["bar", "Foo"]
Jika Anda ingin menjamin urutan yang sama terlepas dari urutan elemen dalam larik input, berikut adalah penyortiran yang stabil :
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;
});
Normalisasi kasus .sort()
dengan .toLowerCase()
.
Anda juga dapat menggunakan operator 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);
Memberi:
biscuit,Bob,charley,fudge,Fudge
Metode localeCompare mungkin baik-baik saja ...
Catatan: Operator Elvis adalah bentuk pendek 'operator ternary' karena jika demikian, biasanya dengan penugasan.
Jika Anda melihat?: Sideways, sepertinya Elvis ...
yaitu bukannya:
if (y) {
x = 1;
} else {
x = 2;
}
kamu bisa memakai:
x = y?1:2;
yaitu ketika y benar, maka kembalikan 1 (untuk penugasan ke x), jika tidak kembalikan 2 (untuk penugasan ke x).
x = y ? y : z
, Anda dapat melakukannya x = y ?: z
. Javascript tidak memiliki operator Elvis yang sebenarnya, tetapi Anda dapat menggunakannya x = y || z
dengan cara yang serupa.
Jawaban lain mengasumsikan bahwa array berisi string. Metode saya lebih baik, karena akan berfungsi walaupun array mengandung null, undefined, atau non-string.
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;
}
The null
akan diurutkan antara 'nulk' dan 'nulm'. Tetapi undefined
akan selalu diurutkan terakhir.
(''+notdefined) === "undefined"
jadi itu akan mengurutkan sebelum "z"
Array.prototype.sort
: | karena bagian tentang (''+notdefined) === "undefined"
benar - benar benar ... yang berarti jika Anda membalik -1 dan 1 dalam fungsi sortir untuk membalik urutan, undefined masih menyortir sampai akhir. Itu juga perlu dipertimbangkan ketika menggunakan fungsi perbandingan di luar konteks semacam array (seperti ketika saya menemukan pertanyaan ini).
Array.prototype.sort
definisi itu - beberapa komentar lagi. Pertama, tidak perlu untuk (''+a)
- toString()
script ECMAS perlu dipanggil pada elemen sebelum meneruskannya ke compareFn. Kedua, fakta yang ignoreCase
kembali 1
ketika membandingkan string yang sama (termasuk string yang sama tetapi untuk kasus) berarti spesifikasi tidak menentukan hasil jika ada nilai duplikat (mungkin akan baik-baik saja hanya dengan beberapa swap yang tidak perlu terjadi, saya pikir).
undefined
adalah kasus khusus, yang untuk x x <undefined dan x> undefined keduanya salah . Itu undefined
selalu yang terakhir, adalah produk sampingan dari implementasi semacam sort. Saya mencoba mengubah ('' a) menjadi sekadar, tetapi gagal. saya mengerti TypeError: a.toUpperCase is not a function
. Ternyata toString
ini tidak disebut sebelum menelepon compareFn.
undefined
perbandinganFn tidak pernah disebut
Versi ES6:
["Foo", "bar"].sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }))
Untuk mendukung jawaban yang diterima saya ingin menambahkan bahwa fungsi di bawah ini tampaknya mengubah nilai-nilai dalam array asli untuk diurutkan sehingga tidak hanya akan mengurutkan huruf kecil tetapi nilai huruf besar juga akan diubah menjadi huruf kecil. Ini adalah masalah bagi saya karena meskipun saya ingin melihat Mary di sebelah Maria, saya tidak berharap bahwa kasus nilai pertama Mary diubah menjadi huruf kecil.
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
Dalam percobaan saya, fungsi berikut dari jawaban yang diterima mengurutkan dengan benar tetapi tidak mengubah nilai.
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Ini dapat membantu jika Anda kesulitan memahami:
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.
***/
arr.sort(function(a,b) {
a = a.toLowerCase();
b = b.toLowerCase();
if( a == b) return 0;
if( a > b) return 1;
return -1;
});
Dalam fungsi di atas, jika kita hanya membandingkan ketika huruf kecil dua nilai a dan b, kita tidak akan mendapatkan hasil yang cantik.
Contoh, jika array adalah [A, a, B, b, c, C, D, d, e, E] dan kami menggunakan fungsi di atas, kami memiliki persis array itu. Itu tidak mengubah apa pun.
Agar hasilnya adalah [A, a, B, b, C, c, D, d, E, e], kita harus membandingkan lagi ketika dua nilai huruf kecil sama:
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;
}
}
}
Saya membungkus jawaban teratas dalam polyfill sehingga saya bisa memanggil .sortIgnoreCase () pada array string
// Array.sortIgnoreCase() polyfill
if (!Array.prototype.sortIgnoreCase) {
Array.prototype.sortIgnoreCase = function () {
return this.sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
};
}
Bungkus string Anda / /i
. Ini adalah cara mudah menggunakan regex untuk mengabaikan casing