5. 資料結構
***********

這個章節將會更深入的介紹一些你已經學過的東西的細節上，並且加入一些你還
沒有接觸過的部分。


5.1. 進一步了解 List（串列）
============================

List（串列）這個資料型態，具有更多操作的方法。下面條列了所有關於 list
物件的 method：

list.append(x)

   將一個新的項目加到 list 的尾端。等同於 "a[len(a):] = [x]"。

list.extend(iterable)

   將 iterable（可疊代物件）接到 list 的尾端。等同於 "a[len(a):] =
   iterable"。

list.insert(i, x)

   將一個項目插入至 list 中給定的位置。第一個引數為插入處前元素的索引
   值，所以 "a.insert(0, x)"  會插入在 list 首位，而 "a.insert(len(a),
   x)" 則相當於 "a.append(x)"。

list.remove(x)

   刪除 list 中第一個值等於 *x* 的元素。若 list 中無此元素則會觸發
   "ValueError"。

list.pop([i])

   Remove the item at the given position in the list, and return it.
   If no index is specified, "a.pop()" removes and returns the last
   item in the list. It raises an "IndexError" if the list is empty or
   the index is outside the list range.

list.clear()

   刪除 list 中所有項目。這等同於 "del a[:]"。

list.index(x[, start[, end]])

   回傳 list 中第一個值等於 *x* 的項目之索引值（從零開始的索引）。若
   list 中無此項目，則丟出 "ValueError" 錯誤。

   引數 *start* 和 *end* 的定義跟在 slice 表示法中相同，搜尋的動作被這
   兩個引數限定在 list 中特定的子序列。但要注意的是，回傳的索引值是從
   list 的開頭開始算，而不是從 *start* 開始算。

list.count(x)

   回傳 *x* 在 list 中所出現的次數。

list.sort(*, key=None, reverse=False)

   將 list 中的項目排序。（可使用引數來進行客製化的排序，請參考
   "sorted()" 部分的解釋）

list.reverse()

   將 list 中的項目前後順序反過來。

list.copy()

   回傳一個淺複製 (shallow copy) 的 list。等同於 "a[:]"。

以下是一個使用到許多 list 物件方法的例子：

   >>> fruits = ['orange', 'apple', 'pear', 'banana', 'kiwi', 'apple', 'banana']
   >>> fruits.count('apple')
   2
   >>> fruits.count('tangerine')
   0
   >>> fruits.index('banana')
   3
   >>> fruits.index('banana', 4)  # Find next banana starting at position 4
   6
   >>> fruits.reverse()
   >>> fruits
   ['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange']
   >>> fruits.append('grape')
   >>> fruits
   ['banana', 'apple', 'kiwi', 'banana', 'pear', 'apple', 'orange', 'grape']
   >>> fruits.sort()
   >>> fruits
   ['apple', 'apple', 'banana', 'banana', 'grape', 'kiwi', 'orange', 'pear']
   >>> fruits.pop()
   'pear'

你可能會注意到一些方法，像是 "insert"、"remove" 或者是 "sort"，並沒有
印出回傳值，事實上，他們回傳預設值 "None" [1]。這是一個用於 Python 中
所有可變資料結構的設計法則。

另外你可能也會發現，不是所有資料都可以被排序或比較。例如，"[None,
'hello', 10]" 就不可排序，因為整數不能與字串比較，而 *None* 不能與其他
型別比較。有些型別根本就沒有被定義彼此之間的大小順序，例如，"3+4j <
5+7j" 就是一個無效的比較。


5.1.1. 將 List 作為 Stack（堆疊）使用
-------------------------------------

The list methods make it very easy to use a list as a stack, where the
last element added is the first element retrieved ("last-in, first-
out").  To add an item to the top of the stack, use "append()".  To
retrieve an item from the top of the stack, use "pop()" without an
explicit index.  For example:

   >>> stack = [3, 4, 5]
   >>> stack.append(6)
   >>> stack.append(7)
   >>> stack
   [3, 4, 5, 6, 7]
   >>> stack.pop()
   7
   >>> stack
   [3, 4, 5, 6]
   >>> stack.pop()
   6
   >>> stack.pop()
   5
   >>> stack
   [3, 4]


5.1.2. 將 List 作為 Queue（佇列）使用
-------------------------------------

我們也可以將 list 當作 queue（佇列）使用，即最先加入元素最先被取回（先
進先出，"first-in, first-out"）的資料結構。然而，list 在這種使用方式下
效率較差。使用 "append" 和 "pop" 來加入和取出尾端的元素較快，而使用
"insert" 和 "pop" 來插入和取出頭端的元素較慢（因為其他元素都需要挪動一
格）。

如果要實作 queue，請使用 "collections.deque"，其被設計成能快速的從頭尾
兩端加入和取出。例如：

   >>> from collections import deque
   >>> queue = deque(["Eric", "John", "Michael"])
   >>> queue.append("Terry")           # Terry arrives
   >>> queue.append("Graham")          # Graham arrives
   >>> queue.popleft()                 # The first to arrive now leaves
   'Eric'
   >>> queue.popleft()                 # The second to arrive now leaves
   'John'
   >>> queue                           # Remaining queue in order of arrival
   deque(['Michael', 'Terry', 'Graham'])


5.1.3. List Comprehensions（串列綜合運算）
------------------------------------------

List comprehension（串列綜合運算）讓你可以用簡潔的方法創建 list。常見
的應用是基於一個序列或 iterable（可疊代物件），將每一個元素經過某個運
算的結果串接起來成為新的 list，或是創建一個子序列，其每一個元素皆滿足
一個特定的條件。

舉例來說，假設我們要創建一個「平方的 list」：

   >>> squares = []
   >>> for x in range(10):
   ...     squares.append(x**2)
   ...
   >>> squares
   [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

注意這是創建（或覆寫）一個變數叫 "x"，其在迴圈結束後仍然存在。我們可以
這樣產生平方串列而不造成任何 side effects（副作用）：

   squares = list(map(lambda x: x**2, range(10)))

或與此相等的：

   squares = [x**2 for x in range(10)]

這樣更簡潔和易讀。

一個 list comprehension 的組成，是在一對方括號內，放入一個 expression
（運算式）、一個 "for" 子句、再接著零個或多個 "for" 或 "if" 子句。結果
會是一個新的 list，內容是在後面的 "for" 和 "if" 子句情境下，對前面運算
式求值的結果。例如，這個 list comprehension 組合了兩個 list 中彼此相異
的元素：

   >>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
   [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

而它就等於：

   >>> combs = []
   >>> for x in [1,2,3]:
   ...     for y in [3,1,4]:
   ...         if x != y:
   ...             combs.append((x, y))
   ...
   >>> combs
   [(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

注意 "for" 和 "if" 在這兩段程式裡的順序是相同的。

如果 expression 是一個 tuple（例如上面例子中的 "(x, y)"），它必須加上
括號：

   >>> vec = [-4, -2, 0, 2, 4]
   >>> # create a new list with the values doubled
   >>> [x*2 for x in vec]
   [-8, -4, 0, 4, 8]
   >>> # filter the list to exclude negative numbers
   >>> [x for x in vec if x >= 0]
   [0, 2, 4]
   >>> # apply a function to all the elements
   >>> [abs(x) for x in vec]
   [4, 2, 0, 2, 4]
   >>> # call a method on each element
   >>> freshfruit = ['  banana', '  loganberry ', 'passion fruit  ']
   >>> [weapon.strip() for weapon in freshfruit]
   ['banana', 'loganberry', 'passion fruit']
   >>> # create a list of 2-tuples like (number, square)
   >>> [(x, x**2) for x in range(6)]
   [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
   >>> # the tuple must be parenthesized, otherwise an error is raised
   >>> [x, x**2 for x in range(6)]
     File "<stdin>", line 1
       [x, x**2 for x in range(6)]
        ^^^^^^^
   SyntaxError: did you forget parentheses around the comprehension target?
   >>> # flatten a list using a listcomp with two 'for'
   >>> vec = [[1,2,3], [4,5,6], [7,8,9]]
   >>> [num for elem in vec for num in elem]
   [1, 2, 3, 4, 5, 6, 7, 8, 9]

List comprehensions 可以含有複雜的 expression 和巢狀的函式：

   >>> from math import pi
   >>> [str(round(pi, i)) for i in range(1, 6)]
   ['3.1', '3.14', '3.142', '3.1416', '3.14159']


5.1.4. 巢狀的 List Comprehensions
---------------------------------

在 list comprehesion 中開頭的 expression 可以是任何形式的 expression，
包括再寫一個 list comprehension。

考慮以下表示 3x4 矩陣的範例，使用 list 包含 3 個長度為 4 的 list ：

   >>> matrix = [
   ...     [1, 2, 3, 4],
   ...     [5, 6, 7, 8],
   ...     [9, 10, 11, 12],
   ... ]

以下的 list comprehesion 會將矩陣的行與列作轉置：

   >>> [[row[i] for row in matrix] for i in range(4)]
   [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

如同我們在上一節看到的，內部的 list comprehension 會依據後面的 "for"
環境被求值，所以這個例子就等於：

   >>> transposed = []
   >>> for i in range(4):
   ...     transposed.append([row[i] for row in matrix])
   ...
   >>> transposed
   [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

而它也和這一段相同：

   >>> transposed = []
   >>> for i in range(4):
   ...     # the following 3 lines implement the nested listcomp
   ...     transposed_row = []
   ...     for row in matrix:
   ...         transposed_row.append(row[i])
   ...     transposed.append(transposed_row)
   ...
   >>> transposed
   [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]

在實際運用上，我們傾向於使用內建函式 (built-in functions) 而不是複雜的
流程控制陳述式。在這個例子中，使用 "zip()" 函式會非常有效率：

   >>> list(zip(*matrix))
   [(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]

關於星號的更多細節，請參考拆解引數列表（Unpacking Argument Lists）。


5.2. "del" 陳述式
=================

There is a way to remove an item from a list given its index instead
of its value: the "del" statement.  This differs from the "pop()"
method which returns a value.  The "del" statement can also be used to
remove slices from a list or clear the entire list (which we did
earlier by assignment of an empty list to the slice).  For example:

   >>> a = [-1, 1, 66.25, 333, 333, 1234.5]
   >>> del a[0]
   >>> a
   [1, 66.25, 333, 333, 1234.5]
   >>> del a[2:4]
   >>> a
   [1, 66.25, 1234.5]
   >>> del a[:]
   >>> a
   []

"del" 也可以用來刪除整個變數：

   >>> del a

刪除之後，對 "a" 的參照將會造成錯誤（至少在另一個值又被指派到它之前）
。我們將在後面看到更多關於 "del" 的其他用法。


5.3. Tuples 和序列 (Sequences)
==============================

我們看到 list 和字串 (string) 有許多共同的特性，像是索引操作
(indexing) 以及切片操作 (slicing) 。他們是*序列*資料類型中的兩個例子（
請參考Sequence Types --- list, tuple, range）。由於 Python 是個持續發
展中的語言，未來可能還會有其他的序列資料類型加入。接著要介紹是下一個標
準序列資料類型：*tuple*。

一個 tuple 是由若干個值藉由逗號區隔而組成，例如：

   >>> t = 12345, 54321, 'hello!'
   >>> t[0]
   12345
   >>> t
   (12345, 54321, 'hello!')
   >>> # Tuples may be nested:
   ... u = t, (1, 2, 3, 4, 5)
   >>> u
   ((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
   >>> # Tuples are immutable:
   ... t[0] = 88888
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: 'tuple' object does not support item assignment
   >>> # but they can contain mutable objects:
   ... v = ([1, 2, 3], [3, 2, 1])
   >>> v
   ([1, 2, 3], [3, 2, 1])

如同我們看到的，被輸出的 tuple 總是以括號包著，如此巢狀的 tuple 才能被
正確的直譯 (interpret)；他們可以是以被括號包著或不被包著的方式當作輸入
，雖然括號的使用常常是有其必要的（譬如此 tuple 是一個較大的運算式的一
部分）。指派東西給 tuple 中的個別項目是不行的，但是可以建立含有可變物
件（譬如 list）的 tuple。

雖然 tuple 和 list 看起來很類似，但是他們通常用在不同的情況與不同目的
。 tuple 是 *immutable*（不可變的），通常儲存異質的元素序列，並可經由
拆解 (unpacking)（請參考本節後段）或索引 (indexing) 來存取（或者在使用
"namedtuples" 的時候藉由屬性 (attribute) 來存取）。List 是 *mutable*（
可變的），其元素通常是同質的且可藉由疊代整個 list 來存取。

一個特別的議題是，關於創建一個含有 0 個或 1 個項目的 tuple：語法上會採
納一些奇怪的用法。空的 tuple 藉由一對空括號來創建；含有一個項目的
tuple 經由一個值加上一個逗點來創建（用括號把一個單一的值包住是不夠的）
。醜，但有效率。例如：

   >>> empty = ()
   >>> singleton = 'hello',    # <-- note trailing comma
   >>> len(empty)
   0
   >>> len(singleton)
   1
   >>> singleton
   ('hello',)

陳述式 "t = 12345, 54321, 'hello!'" 就是一個 *tuple packing* 的例子：
"12345"，"54321" 和 "'hello!'" 一起被放進 tuple 裡。反向操作也可以：

   >>> x, y, z = t

這個正是我們所說序列拆解 (*sequence unpacking*)，可運用在任何位在等號
右邊的序列。序列拆解要求等號左邊的變數數量必須與等號右邊的序列中的元素
數量相同。注意，多重指派就只是 tuple packing 和序列拆解的結合而已。


5.4. 集合 (Sets)
================

Python 也包含了一種用在 *set*（集合）的資料類型。一個 set 是一組無序且
沒有重複的元素。基本的使用方式包括了成員測試和消除重複元素。 Set 物件
也支援聯集、交集、差集和互斥等數學運算。

大括號或 "set()" 函式都可以用來創建 set。注意：要創建一個空的 set，你
必須使用 "set()" 而不是 "{}"；後者會創建一個空的 dictionary，一種我們
將在下一節討論的資料結構。

這裡是一個簡單的演示：

   >>> basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
   >>> print(basket)                      # show that duplicates have been removed
   {'orange', 'banana', 'pear', 'apple'}
   >>> 'orange' in basket                 # fast membership testing
   True
   >>> 'crabgrass' in basket
   False

   >>> # Demonstrate set operations on unique letters from two words
   ...
   >>> a = set('abracadabra')
   >>> b = set('alacazam')
   >>> a                                  # unique letters in a
   {'a', 'r', 'b', 'c', 'd'}
   >>> a - b                              # letters in a but not in b
   {'r', 'd', 'b'}
   >>> a | b                              # letters in a or b or both
   {'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
   >>> a & b                              # letters in both a and b
   {'a', 'c'}
   >>> a ^ b                              # letters in a or b but not both
   {'r', 'd', 'b', 'm', 'z', 'l'}

和 list comprehensions 類似，也有 set comprehensions（集合綜合運算）：

   >>> a = {x for x in 'abracadabra' if x not in 'abc'}
   >>> a
   {'r', 'd'}


5.5. 字典（Dictionary）
=======================

Another useful data type built into Python is the *dictionary* (see
Mapping Types --- dict). Dictionaries are sometimes found in other
languages as "associative memories" or "associative arrays".  Unlike
sequences, which are indexed by a range of numbers, dictionaries are
indexed by *keys*, which can be any immutable type; strings and
numbers can always be keys.  Tuples can be used as keys if they
contain only strings, numbers, or tuples; if a tuple contains any
mutable object either directly or indirectly, it cannot be used as a
key. You can't use lists as keys, since lists can be modified in place
using index assignments, slice assignments, or methods like "append()"
and "extend()".

思考 dictionary 最好的方式是把它想成是一組*鍵值*對 (*key: value* pair)
的 set，其中鍵在同一個 dictionary 裡必須是獨一無二的。使用一對大括號可
創建一個空的 dictionary："{}"。將一串由逗號分隔的鍵值對置於大括號則可
初始化字典的鍵值對。這同樣也是字典輸出時的格式。

Dictionary 主要的操作為藉由鍵來儲存一個值並且可藉由該鍵來取出該值。也
可以使用 "del" 來刪除鍵值對。如果我們使用用過的鍵來儲存，該鍵所對應的
較舊的值會被覆蓋。使用不存在的鍵來取出值會造成錯誤。

對 dictionary 使用 "list(d)" 會得到一個包含該字典所有鍵的 list，其排列
順序為插入時的順序。（若想要排序，則使用 "sorted(d)" 代替即可）。如果
想確認一個鍵是否已存在於字典中，可使用關鍵字 "in"。

這是個使用一個 dictionary 的簡單範例：

   >>> tel = {'jack': 4098, 'sape': 4139}
   >>> tel['guido'] = 4127
   >>> tel
   {'jack': 4098, 'sape': 4139, 'guido': 4127}
   >>> tel['jack']
   4098
   >>> del tel['sape']
   >>> tel['irv'] = 4127
   >>> tel
   {'jack': 4098, 'guido': 4127, 'irv': 4127}
   >>> list(tel)
   ['jack', 'guido', 'irv']
   >>> sorted(tel)
   ['guido', 'irv', 'jack']
   >>> 'guido' in tel
   True
   >>> 'jack' not in tel
   False

函式 "dict()" 可直接透過一串鍵值對序列來創建 dictionary：

   >>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
   {'sape': 4139, 'guido': 4127, 'jack': 4098}

此外，dict comprehensions 也可以透過任意鍵與值的運算式來創建
dictionary ：

   >>> {x: x**2 for x in (2, 4, 6)}
   {2: 4, 4: 16, 6: 36}

當鍵是簡單的字串時，使用關鍵字引數 (keyword arguments) 有時會較為簡潔
：

   >>> dict(sape=4139, guido=4127, jack=4098)
   {'sape': 4139, 'guido': 4127, 'jack': 4098}


5.6. 迴圈技巧
=============

When looping through dictionaries, the key and corresponding value can
be retrieved at the same time using the "items()" method.

   >>> knights = {'gallahad': 'the pure', 'robin': 'the brave'}
   >>> for k, v in knights.items():
   ...     print(k, v)
   ...
   gallahad the pure
   robin the brave

當對序列作迴圈時，位置索引及其對應的值可以藉由使用 "enumerate()" 函式
來同時取得：

   >>> for i, v in enumerate(['tic', 'tac', 'toe']):
   ...     print(i, v)
   ...
   0 tic
   1 tac
   2 toe

要同時對兩個以上的序列作迴圈，可以將其以成對的方式放入 "zip()" 函式：

   >>> questions = ['name', 'quest', 'favorite color']
   >>> answers = ['lancelot', 'the holy grail', 'blue']
   >>> for q, a in zip(questions, answers):
   ...     print('What is your {0}?  It is {1}.'.format(q, a))
   ...
   What is your name?  It is lancelot.
   What is your quest?  It is the holy grail.
   What is your favorite color?  It is blue.

要對序列作反向的迴圈，首先先寫出正向的序列，再對其使用 "reversed()" 函
式：

   >>> for i in reversed(range(1, 10, 2)):
   ...     print(i)
   ...
   9
   7
   5
   3
   1

要以迴圈對序列作排序，使用 "sorted()" 函式會得到一個新的經排序過的
list ，但不會改變原本的序列：

   >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
   >>> for i in sorted(basket):
   ...     print(i)
   ...
   apple
   apple
   banana
   orange
   orange
   pear

對序列使用 "set()" 可去除重複元素。對序列使用 "sorted()" 加上 "set()"
，則是對經過排序後的非重複元素跑迴圈的慣用方法：

   >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
   >>> for f in sorted(set(basket)):
   ...     print(f)
   ...
   apple
   banana
   orange
   pear

有時我們會想要以迴圈來改變的一個 list，但是，通常創建一個新的 list 會
更簡單且安全：

   >>> import math
   >>> raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
   >>> filtered_data = []
   >>> for value in raw_data:
   ...     if not math.isnan(value):
   ...         filtered_data.append(value)
   ...
   >>> filtered_data
   [56.2, 51.7, 55.3, 52.5, 47.8]


5.7. 深入了解條件 (Condition)
=============================

使用在 "while" 和 "if" 陳述式的條件句可以包含任何運算子，而不是只有比
較運算子 (comparisons) 。

比較運算子 "in" 和 "not in" 用於成員檢查，在容器中檢查一個值是否存在（
或不存在）。運算子 "is" 和 "is not" 比較兩個物件是否真的是相同的物件。
所有比較運算子的優先度都相同且都低於數值運算子。

比較運算是可以串連在一起的。例如， "a < b == c" 就是在測試 "a" 是否小
於 "b" 和 "b" 是否等於 "c"。

比較運算可以結合布林運算子 "and" 和 "or"，且一個比較運算的結果（或任何
其他布林運算式）可以加上 "not" 來否定。這些運算子的優先度都比比較運算
子還低，其中，"not" 的優先度最高，"or" 的優先度最低，因此 "A and not B
or C" 等同於 "(A and (not B)) or C"。一如往常，括號可以用來表示任何想
要的組合。

布林運算子 "and" 和 "or" 也被稱為*短路 (short-circuit)* 運算子：會將其
引數從左至右進行運算，當結果出現時即結束運算。例如，若 "A" 和 "C" 為真
但 "B" 為假，則 "A and B and C" 的運算並不會執行到 "C"。當運算結果被當
成一般值而非布林值時，短路運算子的回傳值為最後被求值的引數。

將一個比較運算或其他布林運算式的結果指派給一個變數是可以的。例如：

   >>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
   >>> non_null = string1 or string2 or string3
   >>> non_null
   'Trondheim'

注意，Python 與 C 語言不一樣，在運算式裡進行指派必須外顯地使用海象運算
子 ":="。 這樣做避免了在 C 語言裡常見的一種問題：想要打 "==" 卻在運算
式裡輸入 "="。


5.8. 序列和其他資料類型之比較
=============================

序列物件通常可以拿來和其他相同類型的物件做比較。這種比較使用*詞典式
(lexicographical)* 順序：首先比較各自最前面的那項，若不相同，便可決定
結果；若相同，則比較下一項，以此類推，直到其中一個序列完全用完。如果被
拿出來比較的兩項本身又是相同的序列類型，則詞典式比較會遞迴地執行。如果
兩個序列所有的項目都相等，則此兩個序列被認為是相等的。如果其中一個序列
是另一個的子序列，則較短的那個序列為較小的序列。字串的詞典式順序使用
Unicode 的碼位 (code point) 編號來排序個別字元。以下是一些相同序列類型
的比較：

   (1, 2, 3)              < (1, 2, 4)
   [1, 2, 3]              < [1, 2, 4]
   'ABC' < 'C' < 'Pascal' < 'Python'
   (1, 2, 3, 4)           < (1, 2, 4)
   (1, 2)                 < (1, 2, -1)
   (1, 2, 3)             == (1.0, 2.0, 3.0)
   (1, 2, ('aa', 'ab'))   < (1, 2, ('abc', 'a'), 4)

注意，若使用 "<" 或 ">" 來比較不同類型的物件是合法的，表示物件擁有適當
的比較方法。例如，混合的數值類型是根據它們數值來做比較，所以 0 等於
0.0，等等。否則直譯器會選擇丟出一個 "TypeError" 錯誤而不是提供一個任意
的排序。

-[ 註解 ]-

[1] 其他語言可以回傳變更後的物件，這就允許 method 的串連，例如
    "d->insert("a")->remove("b")->sort();"。
