Tôi có một chuỗi các chuỗi tôi cần sắp xếp trong JavaScript, nhưng theo cách không phân biệt chữ hoa chữ thường. Làm thế nào để thực hiện điều này?
Tôi có một chuỗi các chuỗi tôi cần sắp xếp trong JavaScript, nhưng theo cách không phân biệt chữ hoa chữ thường. Làm thế nào để thực hiện điều này?
Câu trả lời:
Trong (gần như :) một lót
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Kết quả nào
[ 'bar', 'Foo' ]
Trong khi
["Foo", "bar"].sort();
kết quả trong
[ 'Foo', 'bar' ]
return a.localeCompare(b, 'en', {'sensitivity': 'base'});
toLowerCase()
khi localeCompare
đã làm điều đó theo mặc định trong một số trường hợp. Bạn có thể đọc thêm về các tham số để truyền tới nó tại đây: 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: Xin lưu ý rằng ban đầu tôi đã viết điều này để minh họa cho kỹ thuật hơn là có hiệu suất trong tâm trí. Vui lòng tham khảo câu trả lời @Ivan Krechetov để có giải pháp nhỏ gọn hơn.
toLowerCase
hai lần trên mỗi chuỗi; sẽ hiệu quả hơn khi lưu trữ các phiên bản thấp hơn của chuỗi trong các biến.
.toLowerCase()
nhiều lần cho mỗi mục trong mảng. Ví dụ: 45 cuộc gọi đến chức năng so sánh khi sắp xếp 10 mục theo thứ tự ngược lại. 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
Đã đến lúc xem lại câu hỏi cũ này.
Bạn không nên sử dụng các giải pháp dựa vào toLowerCase
. Chúng không hiệu quả và đơn giản là không hoạt động trong một số ngôn ngữ (ví dụ tiếng Thổ Nhĩ Kỳ). Thích điều này:
['Foo', 'bar'].sort((a, b) => a.localeCompare(b, undefined, {sensitivity: 'base'}))
Kiểm tra tài liệu về tính tương thích của trình duyệt và tất cả những điều cần biết về sensitivity
tùy chọn này.
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"]
, chúng tôi có thể muốn nó trả về ["111", "33"]
vì 1 đến trước 3 trong thứ tự mã ký tự. Tuy nhiên, hàm trong câu trả lời này sẽ trả về ["33", "111"]
vì số 33
này nhỏ hơn số 111
.
"33" > "111" === true
và 33 > 111 === false
. Nó hoạt động như dự định.
Bạn cũng có thể sử dụng mới Intl.Collator().compare
, trên mỗi MDN, nó hiệu quả hơn khi sắp xếp các mảng. Nhược điểm là nó không được hỗ trợ bởi các trình duyệt cũ hơn. MDN tuyên bố rằng nó hoàn toàn không được hỗ trợ trong Safari. Cần xác minh nó, vì nó nói rằng Intl.Collator
được hỗ trợ.
Khi so sánh số lượng lớn các chuỗi, chẳng hạn như trong việc sắp xếp các mảng lớn, tốt hơn là tạo một đối tượng Intl.Collator và sử dụng hàm được cung cấp bởi thuộc tính so sánh của nó
["Foo", "bar"].sort(Intl.Collator().compare); //["bar", "Foo"]
Nếu bạn muốn đảm bảo cùng một thứ tự bất kể thứ tự các phần tử trong mảng đầu vào, đây là cách sắp xếp ổn định :
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;
});
Bình thường hóa trường hợp trong .sort()
với .toLowerCase()
.
Bạn cũng có thể sử dụng toán tử 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);
Cung cấp:
biscuit,Bob,charley,fudge,Fudge
Phương thức localeCompare có lẽ vẫn ổn mặc dù ...
Lưu ý: Toán tử Elvis là một dạng "toán tử ternary" dạng ngắn, nếu sau đó, thường là với phép gán.
Nếu bạn nhìn vào ?: Đi ngang, có vẻ như Elvis ...
tức là thay vì:
if (y) {
x = 1;
} else {
x = 2;
}
bạn có thể dùng:
x = y?1:2;
tức là khi y đúng, sau đó trả về 1 (đối với gán cho x), nếu không thì trả về 2 (đối với gán cho x).
x = y ? y : z
, bạn có thể làm x = y ?: z
. Javascript không có toán tử Elvis thực tế, nhưng bạn có thể sử dụng x = y || z
theo cách tương tự.
Các câu trả lời khác cho rằng mảng chứa chuỗi. Phương thức của tôi tốt hơn, bởi vì nó sẽ hoạt động ngay cả khi mảng chứa null, không xác định hoặc các chuỗi không khác.
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;
}
Các null
sẽ được sắp xếp giữa 'nulk' và 'nulm'. Nhưng undefined
sẽ luôn luôn được sắp xếp cuối cùng.
(''+notdefined) === "undefined"
vì vậy nó sẽ sắp xếp trước "z"
Array.prototype.sort
: | bởi vì phần (''+notdefined) === "undefined"
thực sự là đúng ... có nghĩa là nếu bạn lật -1 và 1 trong hàm sắp xếp để đảo ngược thứ tự, không xác định vẫn sắp xếp đến cuối. Nó cũng cần được xem xét khi sử dụng hàm so sánh bên ngoài ngữ cảnh của một loại sắp xếp mảng (như tôi đã từng gặp khi đặt câu hỏi này).
Array.prototype.sort
định nghĩa đó - vài ý kiến thêm. Đầu tiên, không cần phải có (''+a)
- ECMAScript yêu cầu toString()
được gọi trên các phần tử trước khi chuyển chúng vào notifyFn. Thứ hai, thực tế là ignoreCase
trả về 1
khi so sánh các chuỗi bằng nhau (bao gồm cả các trường hợp bằng nhau) có nghĩa là đặc tả không xác định kết quả nếu có các giá trị trùng lặp (có thể sẽ ổn chỉ với một số giao dịch hoán đổi không cần thiết xảy ra, tôi nghĩ vậy).
undefined
là một trường hợp đặc biệt, với mọi x x <không xác định và x> không xác định đều sai . Điều đó undefined
luôn luôn là cuối cùng, là sản phẩm phụ của việc thực hiện sắp xếp sắp xếp. Tôi đã cố gắng thay đổi ('' + a) thành đơn giản là a, nhưng không thành công. tôi nhận được TypeError: a.toUpperCase is not a function
. Rõ ràng toString
là không được gọi trước khi gọi so sánhFn.
undefined
so sánh, không bao giờ được gọi
Phiên bản ES6:
["Foo", "bar"].sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' }))
Để hỗ trợ cho câu trả lời được chấp nhận, tôi muốn thêm rằng hàm bên dưới dường như thay đổi các giá trị trong mảng ban đầu được sắp xếp để không chỉ sắp xếp chữ thường mà các giá trị chữ hoa cũng sẽ được thay đổi thành chữ thường. Đây là một vấn đề đối với tôi bởi vì mặc dù tôi muốn thấy Mary bên cạnh mary, tôi không muốn rằng trường hợp của giá trị đầu tiên Mary được thay đổi thành chữ thường.
myArray.sort(
function(a, b) {
if (a.toLowerCase() < b.toLowerCase()) return -1;
if (a.toLowerCase() > b.toLowerCase()) return 1;
return 0;
}
);
Trong các thí nghiệm của tôi, hàm sau từ câu trả lời được chấp nhận sắp xếp chính xác nhưng không thay đổi các giá trị.
["Foo", "bar"].sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
Điều này có thể giúp đỡ nếu bạn đã đấu tranh để hiểu:
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;
});
Trong hàm trên, nếu chúng ta chỉ so sánh khi chữ thường hai giá trị a và b, chúng ta sẽ không có kết quả đẹp.
Ví dụ, nếu mảng là [A, a, B, b, c, C, D, d, e, E] và chúng tôi sử dụng hàm trên, chúng tôi có chính xác mảng đó. Nó không thay đổi gì cả.
Để có kết quả là [A, a, B, b, C, c, D, d, E, e], chúng ta nên so sánh lại khi hai giá trị chữ thường bằng nhau:
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;
}
}
}
Tôi gói câu trả lời hàng đầu trong một polyfill để tôi có thể gọi .sortIgnoreCase () trên mảng chuỗi
// Array.sortIgnoreCase() polyfill
if (!Array.prototype.sortIgnoreCase) {
Array.prototype.sortIgnoreCase = function () {
return this.sort(function (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
});
};
}
Quấn dây của bạn vào / /i
. Đây là một cách dễ dàng để sử dụng regex để bỏ qua vỏ