Thứ hai, 06/08/2018 | 00:00 GMT+7

Sử dụng phương pháp sắp xếp của JavaScript để sắp xếp các mảng chuỗi


Phương thức sort có sẵn trên nguyên mẫu Mảng cho phép bạn sắp xếp các phần tử của một mảng. Nó chấp nhận một chức năng gọi lại tùy chọn mà bạn có thể sử dụng để điều chỉnh cơ chế sắp xếp theo nhu cầu cụ thể của bạn .

Đối với mảng số, hãy tham khảo bài đăng trước của ta về cách sắp xếp mảng số .

Việc sắp xếp các chuỗi có thể khá khó hiểu vì cách thức hoạt động của phương pháp sort .

Đầu tiên, tiêu chuẩn ECMAScript không chỉ định một thuật toán sắp xếp cụ thể, tất cả phụ thuộc vào từng nhà cung cấp trình duyệt.

Thứ hai, vỏ đóng một role quan trọng khi phân loại. Để việc sắp xếp hoạt động, cần phải có sự sắp xếp theo thứ tự của các thứ và điều này có thể đạt được với các con số - các con số liên tục tự nhiên (1, 2, 3, 4…). Khi các chuỗi đang được so sánh, chúng được chuyển đổi thành giá trị Unicode tương đương - không có gì đáng ngạc nhiên là các số, sau đó được sắp xếp tuần tự, theo thứ tự tăng dần theo mặc định.

Giá trị Unicode cho các ký tự

Để lấy giá trị Unicode của mỗi ký tự - viết thường hoặc viết hoa, ta sử dụng phương thức chuỗi charCodeAt để truy cập mã ký tự của một index ký tự được chỉ định.

Ở lại với tôi.

Ta sẽ bắt đầu bằng cách tạo các hàm tiện ích giúp lấy các giá trị unicode của các ký tự cũng như các ký tự. Ta sẽ đề cập đến chúng khi ta đi.

// get Unicode values of character items in an array
function getCharactersUnicodeValue(characters) {
  const unicodeChart = new Map();
  characters.forEach(character => {
    unicodeChart.set(
      character,
      character.charCodeAt(character.indexOf(character))
    );
  });
  console.table(unicodeChart);
}

// get unicode values of a single character
function getCharacterUnicodeValue(character) {
  const value = character.charCodeAt(character.indexOf(character));
  console.log(value);
}

Lưu ý việc sử dụng Bản đồ tại đây.


Ta sẽ gọi các chức năng tiện ích như:

getCharactersUnicodeValue("ABCDEFabcdef".split("")); // array of characters: [ 'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f' ]
// Result: {character → Unicode Value}
// { A → 65, B → 66, C → 67, D → 68, E → 69, F → 70, a → 97, b → 98, c → 99, d → 100, e → 101, f → 102 }

getCharacterUnicodeValue("A");
// Result: {character → Unicode Value}
// { A → 65 }

Và đây là một ví dụ khác:

const crocodilian = "crOCoDiliaN".split(""); // array of characters i.e [ 'c', 'r', 'O', 'C', 'o', 'D', 'i', 'l', 'i', 'a', 'N' ]

getCharactersUnicodeValue(crocodilian);

// Result: {character → Unicode Value}
// { c → 99, r → 114, O → 79, C → 67, o → 111, D → 68, i → 105, l → 108, a → 97, N → 78 }

Lưu ý các ký tự UPPERCASE xuất hiện trước các tự viết thường . Và họ sẽ đến tuần tự. Nó được sắp xếp như sau: ['Eggs', 'Tail', 'eggs'] . Để ý xem Tail đến trước eggs như thế nào? Điều đó được mong đợi bởi vì:

getCharactersUnicodeValue(["Eggs", "Tail", "eggs"]);

// Result: {character → Unicode Value}
// { Eggs → 69, Tail → 84, eggs → 101 }
// 84 (T) of Tail comes numerically before 101 (e) of eggs

TL; DR : Việc sắp xếp khi một chuỗi chỉ được tạo thành với cùng một trường hợp (viết hoa hoặc viết thường) thật dễ dàng. Thử thách chỉ đến với các trường hợp hỗn hợp.

Sắp xếp các chuỗi trường hợp hỗn hợp

Hầu hết thời gian ta sẽ muốn mảng của ta về trường hợp chuỗi hỗn hợp để được sắp xếp không phụ thuộc vào vỏ.

const things = [ 'nest', 'Eggs', 'bite', 'gator', 'caYman', 'Grip', 'grips', 'Jaw', 'crocodilian', 'Bayou' ];

Cuối cùng sẽ được sắp xếp như sau:

[ 'Bayou', 'bite', 'caYman', 'crocodilian', 'Eggs', 'gator', 'Grip', 'grips', 'Jaw', 'nest' ]

Và không:

[ 'Bayou', 'Eggs', 'Grip', 'Jaw', 'bite', 'caYman', 'crocodilian', 'gator', 'grips', 'nest' ]

Nỗ lực một: Không có chức năng so sánh

Gọi phương thức sắp xếp mà không có hàm so sánh sẽ không hoạt động:

things.sort();

// ['Bayou', 'Eggs', 'Grip', 'Jaw', 'bite', 'caYman', 'crocodilian', 'gator', 'grips', 'nest']

Nỗ lực thứ hai: Với chức năng so sánh

function sortThings(a, b) {
  if (a > b) {
    return 1;
  } else if (a < b) {
    return -1;
  } else if (a === b) {
    return 0;
  }
}

Sau đó sắp xếp bằng comparison function :

things.sort(sortThings);

// [ 'Bayou', 'Eggs', 'Grip', 'Jaw', 'bite', 'caYman', 'crocodilian', 'gator', 'grips', 'nest' ]

Tuy nhiên, nó không hoạt động. Trên thực tế, ta cũng có thể đã không viết một hàm so sánh .

Nỗ lực ba: Với chức năng so sánh và trường hợp chung

Vấn đề là việc sắp xếp vẫn sử dụng các trường hợp hỗn hợp mặc định của các phần tử mảng thứ mà ta cần làm là chuyển đổi các trường hợp thành một trường hợp chung - chữ thường hoặc chữ UPPERCASE sẽ làm.

function sortThings(a, b) {
  a = a.toLowerCase();
  b = b.toLowerCase();

  if (a > b) {
    return 1;
  } else if (a < b) {
    return -1;
  } else if (a === b) {
    return 0;
  }
}

Hoặc, sử dụng toán tử bậc ba:

function sortThings(a, b) {
  a = a.toLowerCase();
  b = b.toLowerCase();

  return a > b ? -1 : b > a ? 1 : 0;
}

Sau đó sắp xếp lại bằng comparison function :

things.sort(sortThings);

// ['Bayou', 'bite', 'caYman', 'crocodilian', 'Eggs', 'gator', 'Grip', 'grips', 'Jaw', 'nest' 'eggz']

Và bạn thấy nó hoạt động ngay bây giờ!

Nhưng xin chờ chút nữa

Mặc dù các nhà cung cấp trình duyệt có thuật toán sắp xếp cụ thể của họ, nhưng có một số kỹ thuật mà ta nên làm quen. Việc sắp xếp được thực hiện trên cơ sở charCodeAt(index) . Trong trường hợp hai mục so sánh gần như tương tự nhau, charCodeAt(index) được so sánh liên tục. Nơi index bắt đầu từ 0 cho đến khi có sự khác biệt.

Lấy eggsEggz làm ví dụ:

  1. Nếu không chuyển đổi thành chữ thường, Eggz sẽ đứng trước eggs vì giá trị Unicode của E → 69 đứng trước giá trị của e → 101 .

  2. Khi có một chuyển đổi sang một trường hợp tương tự - chữ thường ví dụ - ta đang chủ yếu so sánh eggseggz . e → 101e → 101 bằng nhau.

Đang chạy:

['Eggz', 'eggs'].sort(sortThings);

// ['eggs', 'Eggz']

Sắp xếp chính xác với các ký tự cuối cùng s → 115 and z → 122 là các ký tự xác định.

Việc kiểm tra diễn ra như sau:

  • [e → 101] ggs và [e → 101] ggz / 101 === 101, ta chuyển sang các ký tự tiếp theo
  • e [g → 103] gs và e [g → 103] gz / 103 === 103, ta chuyển sang các ký tự tiếp theo
  • ví dụ [g → 103] s và ví dụ [g → 103] z / 103 === 103, ta chuyển sang các ký tự tiếp theo
  • egg [s → 115] và egg [z → 122] / hiển nhiên, 115 đến trước 122.

Et voilà, điều đó quyết định cuộc đấu tay đôi!

Thứ tự giảm dần

Nếu bạn cần sắp xếp theo thứ tự giảm dần, chỉ cần swap trả về 1 trong hàm so sánh với trả về -1 như sau:

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

Hoặc là:

function sortThings(a, b) {
  a = a.toLowerCase();
  b = b.toLowerCase();
  return a > b ? -1 : b > a ? 1 : 0;
}

Hoặc chỉ cần reverse mảng đã sắp xếp bằng phương thức reverse mảng, rõ ràng là đảo ngược mảng thành chuỗi ngược lại:

things.sort(sortThings).reverse();

Thay thế: Sử dụng localeCompare

Mặc dù phương thức chuỗi localeCompare có thể so sánh các ký tự mà không liên quan đến trường hợp được sử dụng, đó là một phương thức chuỗi nên không thể sử dụng trực tiếp trên một mảng. Để sắp xếp mảng things của ta bằng phương thức chuỗi localeCompare , ta chuyển localeCompare làm hàm so sánh như sau:

things.sort((a, b) => a.localeCompare(b));

// [ 'Bayou', 'bite', 'caYman', 'crocodilian', 'Eggs', 'gator', 'Grip', 'grips', 'Jaw', 'nest' ]

Trong nháy mắt mã

const things = [
  "nest",
  "Eggs",
  "bite",
  "gator",
  "caYman",
  "Grip",
  "grips",
  "Jaw",
  "crocodilian",
  "Bayou"
];
console.log(`unsorted: ${things.join(", ")}`);

function sortThings(a, b) {
  a = a.toLowerCase();
  b = b.toLowerCase();
  return a > b ? 1 : b > a ? -1 : 0;
}

console.log(`sorted:  ${things.sort(sortThings).join(", ")}`);

Lưu ý , hãy tiếp tục phân loại, thế giới cần nó.


Tags:

Các tin liên quan