Sắp xếp Python

Cách dễ nhất để sắp xếp là dùng hàm được sắp xếp(list) để nhận danh sách và trả về danh sách mới chứa các phần tử đó theo thứ tự được sắp xếp. Danh sách ban đầu không thay đổi.

  a = [5, 1, 4, 3]
  print(sorted(a))  ## [1, 3, 4, 5]
  print(a)  ## [5, 1, 4, 3]

Thông thường, bạn nên truyền một danh sách vào hàm được sắp xếp(), nhưng trên thực tế, hàm này có thể lấy dữ liệu đầu vào bất kỳ loại bộ sưu tập lặp lại nào. Phương thức list.sort() cũ hơn là một giải pháp thay thế được nêu chi tiết bên dưới. Hàm sort() có vẻ dễ sử dụng hơn so với sort(), vì vậy bạn nên sử dụng sort().

Hàm được sắp xếp() có thể được tuỳ chỉnh thông qua các đối số không bắt buộc. Đối số không bắt buộc được sắp xếp() reverse=True, ví dụ: được sắp xếp(danh sách, reverse=True), sẽ làm cho đối số được sắp xếp ngược lại.

  strs = ['aa', 'BB', 'zz', 'CC']
  print(sorted(strs))  ## ['BB', 'CC', 'aa', 'zz'] (case sensitive)
  print(sorted(strs, reverse=True))   ## ['zz', 'aa', 'CC', 'BB']

Sắp xếp tuỳ chỉnh bằng phím=

Để sắp xếp tuỳ chỉnh phức tạp hơn, sort() sẽ lấy một "key=" (không bắt buộc) chỉ định một hàm "key" để biến đổi từng phần tử trước khi so sánh. Hàm key nhận được 1 giá trị và trả về 1 giá trị, còn giá trị "Proxy" được trả về sẽ được dùng để so sánh trong phạm vi sắp xếp.

Ví dụ: với một danh sách chuỗi, việc chỉ định key=len (hàm len() tích hợp sẵn) sẽ sắp xếp các chuỗi theo độ dài, từ ngắn nhất đến dài nhất. Phương thức sắp xếp này sẽ gọi len() cho mỗi chuỗi để lấy danh sách các giá trị độ dài proxy, sau đó sắp xếp theo các giá trị proxy đó.

  strs = ['ccc', 'aaaa', 'd', 'bb']
  print(sorted(strs, key=len))  ## ['d', 'bb', 'ccc', 'aaaa']

cuộc gọi được sắp xếp bằng key=len

Một ví dụ khác là việc chỉ định "str.lower" làm hàm chính là một cách để buộc chế độ sắp xếp xử lý giống nhau chữ hoa và chữ thường:

  ## "key" argument specifying str.lower function to use for sorting
  print(sorted(strs, key=str.lower))  ## ['aa', 'BB', 'CC', 'zz']

Bạn cũng có thể chuyển MyFn của riêng mình dưới dạng hàm chính như sau:

  ## Say we have a list of strings we want to sort by the last letter of the string.
  strs = ['xc', 'zb', 'yd' ,'wa']

  ## Write a little function that takes a string, and returns its last letter.
  ## This will be the key function (takes in 1 value, returns 1 value).
  def MyFn(s):
    return s[-1]

  ## Now pass key=MyFn to sorted() to sort by the last letter:
  print(sorted(strs, key=MyFn))  ## ['wa', 'zb', 'xc', 'yd']

Để sắp xếp phức tạp hơn như sắp xếp theo họ rồi theo tên, bạn có thể sử dụng các hàm itemgetter hoặc attrgetter như:

  from operator import itemgetter

  # (first name, last name, score) tuples
  grade = [('Freddy', 'Frank', 3), ('Anil', 'Frank', 100), ('Anil', 'Wang', 24)]
  sorted(grade, key=itemgetter(1,0))
  # [('Anil', 'Frank', 100), ('Freddy', 'Frank', 3), ('Anil', 'Wang', 24)]

  sorted(grade, key=itemgetter(0,-1))
  #[('Anil', 'Wang', 24), ('Anil', 'Frank', 100), ('Freddy', 'Frank', 3)]

phương thức sort()

Thay vì sắp xếp(), phương thức sort() trên danh sách sẽ sắp xếp danh sách đó theo thứ tự tăng dần, ví dụ như list.sort(). Phương thức sort() sẽ thay đổi danh sách cơ bản và trả về Không có, vì vậy hãy sử dụng phương thức này như sau:

  alist.sort()            ## correct
  alist = blist.sort()    ## Incorrect. sort() returns None

Ở trên là những hiểu lầm rất phổ biến với sort() -- nó *không trả về* danh sách đã sắp xếp. Phương thức sort() phải được gọi trên một danh sách; phương thức này không hoạt động trên bất kỳ tập hợp nào có thể đếm được (nhưng hàm được sort() ở trên thì hoạt động trên bất cứ thứ gì). Phương thức sắp xếp() có trước hàm được sắp xếp() nên bạn có thể thấy phương thức này trong mã cũ hơn. Phương thức sort() không cần tạo danh sách mới, vì vậy có thể nhanh hơn một chút trong trường hợp các phần tử cần sắp xếp đã có trong danh sách.

Cặp âm thanh

Bộ dữ liệu là một nhóm các phần tử có kích thước cố định, chẳng hạn như toạ độ (x, y). Tuples giống như danh sách, ngoại trừ việc chúng là bất biến và không thay đổi kích thước (tuples không hoàn toàn là bất biến vì một trong các phần tử chứa trong đó có thể thay đổi được). Cặp giá trị (Tuple) đóng một loại vai trò "cấu trúc" trong Python – một cách thuận tiện để truyền một gói giá trị có kích thước cố định, hợp lý. Một hàm cần trả về nhiều giá trị có thể chỉ trả về một bộ giá trị. Ví dụ: nếu tôi muốn có một danh sách các toạ độ 3d, thì đại diện python tự nhiên sẽ là một danh sách các bộ dữ liệu, trong đó mỗi bộ dữ liệu có kích thước 3 giữ một nhóm (x, y, z).

Để tạo một bộ dữ liệu, chỉ cần liệt kê các giá trị trong dấu ngoặc đơn được phân tách bằng dấu phẩy. Bộ dữ liệu "trống" chỉ là một cặp dấu ngoặc đơn trống. Việc truy cập các phần tử trong một bộ dữ liệu cũng giống như danh sách – len(), [ ], for, in, v.v. tất cả đều hoạt động như nhau.

  tuple = (1, 2, 'hi')
  print(len(tuple))  ## 3
  print(tuple[2])    ## hi
  tuple[2] = 'bye'  ## NO, tuples cannot be changed
  tuple = (1, 2, 'bye')  ## this works

Để tạo bộ dữ liệu kích thước 1, phần tử đơn lẻ phải được theo sau bằng dấu phẩy.

  tuple = ('hi',)   ## size-1 tuple

Đây là một trường hợp hài hước về cú pháp, nhưng dấu phẩy là cần thiết để phân biệt bộ dữ liệu với trường hợp thông thường của việc đặt một biểu thức trong dấu ngoặc đơn. Trong một số trường hợp, bạn có thể bỏ qua dấu ngoặc đơn và Python sẽ thấy từ dấu phẩy mà bạn dự định sử dụng một bộ dữ liệu.

Việc chỉ định một bộ dữ liệu cho một bộ dữ liệu có kích thước giống hệt nhau của các tên biến sẽ chỉ định tất cả các giá trị tương ứng. Nếu bộ dữ liệu không có cùng kích thước thì sẽ xảy ra lỗi. Tính năng này cũng áp dụng cho các danh sách.

  (x, y, z) = (42, 13, "hike")
  print(z)  ## hike
  (err_string, err_code) = Foo()  ## Foo() returns a length-2 tuple

Liệt kê nội dung hiểu (không bắt buộc)

Mức độ hiểu danh sách là một tính năng nâng cao hơn, hữu ích cho một số trường hợp nhưng không cần thiết cho bài tập và không phải là thứ bạn cần học trước (tức là bạn có thể bỏ qua phần này). Hiểu danh sách là một cách ngắn gọn để viết một biểu thức mở rộng thành toàn bộ danh sách. Giả sử chúng ta có một danh sách số [1, 2, 3, 4], dưới đây là khả năng hiểu danh sách để tính danh sách các bình phương của chúng [1, 4, 9, 16]:

  nums = [1, 2, 3, 4]

  squares = [ n * n for n in nums ]   ## [1, 4, 9, 16]

Cú pháp là [ expr for var in list ]for var in list trông giống như một vòng lặp for thông thường, nhưng không có dấu hai chấm (:). expr ở bên trái được đánh giá một lần cho mỗi phần tử để cung cấp giá trị cho danh sách mới. Dưới đây là ví dụ về chuỗi, trong đó mỗi chuỗi được thay đổi thành chữ hoa và có thêm '!!!':

  strs = ['hello', 'and', 'goodbye']

  shouting = [ s.upper() + '!!!' for s in strs ]
  ## ['HELLO!!!', 'AND!!!', 'GOODBYE!!!']

Bạn có thể thêm một lượt kiểm thử if ở bên phải vòng lặp để thu hẹp kết quả. Kết quả kiểm thử if được đánh giá cho từng phần tử, chỉ bao gồm các phần tử có kết quả kiểm thử đúng.

  ## Select values <= 2
  nums = [2, 8, 1, 6]
  small = [ n for n in nums if n <= 2 ]  ## [2, 1]

  ## Select fruits containing 'a', change to upper case
  fruits = ['apple', 'cherry', 'banana', 'lemon']
  afruits = [ s.upper() for s in fruits if 'a' in s ]
  ## ['APPLE', 'BANANA']

Bài tập: list1.py

Để thực hành nội dung trong phần này, hãy thử các bài toán sau trong list1.py sử dụng tính năng sắp xếp và bộ dữ liệu (trong Bài tập cơ bản).