Python 中list.sort和sorted以及bisect
list.sort方法和內置函數sorted
list.sort方法會就地排序列表,也就是說不會把原列表復制一份.這也是這個方法的返回值是None的原因,提醒你本方法不會新建一個列表.
在這種情況下返回None其實是Python的一個慣例: 如果一個函數或者方法對對象進行的是就地改動,那么它就應該返回None,好讓調用者知道傳入的參數發生了變動,并且并未產生新的對象.
與list.sort相反的是內置函數sorted(),它會新建一個列表作為返回值.這個方法可以接受任何形式的可迭代對象作為參數,甚至包括不可變序列或生成器.
而不管sorted接受的是怎樣的參數,它最后都會返回一個列表.
不管是list.sort還是sorted函數,都有兩個可選的關鍵字參數
- reverse: 如果被設定為True,被排序的序列里的元素會以降序輸出,這個參數的默認值是False
- key: 一個只有一個參數的函數,這個函數會被用在序列里的每一個元素上,所產生的結果將是排序算法依賴的對比關鍵字.
比如說,在對一些字符串排序時,可以用key=str.lower來實現忽略大小寫的排序,或者用key=len進行基于字符串長度的排序
這個參數的默認值是恒等函數,也就是默認用元素自己的值來排序.
下面通過幾個小例子來看看這兩個函數和它們的關鍵字參數
fruits = ["grape", "raspberry", "apple", "banana"] print(sorted(fruits)) # 新建了一個按照字母排序的字符串列表 print(fruits) # 原列表沒有變化 print(sorted(fruits, reverse=True)) # 按照字母降序排列 print(sorted(fruits, key=len)) # 新建一個按照長度排序的字符串列表.因為這個排序算法是穩定的,grape和apple的長度都是5,它們的相對位置跟在原來的列表里是一樣的. print(sorted(fruits, key=len, reverse=True)) # 按照長度降序排列,結果并不上上面那個結果的完全翻轉,因為用到的排序算法是穩定的,也就是說在長度一樣時,grape和apple的相對位置不會改變. print(fruits.sort()) # 對原列表進行就地排序,返回值是None print(fruits) # 此時fruits本身被排序已排序的序列可以用來進行快速搜索,而標準庫的bisect模塊給我們提供了二分查找法.
用bisect來管理已排序的序列 bisect模塊包含兩個主要函數,bisect和insort,兩個函數都利用二分查找法來在有序序列中查找和插入元素
bisect(haystack, needle)在haystack里搜索needle的位置,該位置滿足的條件是,把needle插入這個位置后,haystack還能保持升序.
也就是說這個函數返回的位置前面的值,都小于或等于needle的值.
可以使用bisect(haystack, needle)來查找位置index,再用haystack.insert(index, needle)來插入新值.但是也可以用insort來一步到位,并且后者的速度會快一點.
''' 學習中遇到問題沒人解答?小編創建了一個Python學習交流QQ群:725638078 尋找有志同道合的小伙伴,互幫互助,群里還有不錯的視頻學習教程和PDF電子書! ''' import bisect import sysHAYSTACK = [1, 4, 5, 6, 8, 12, 15, 20, 21, 23, 23, 26, 29, 30] NEEDLES = [0, 1, 2, 5, 8, 10, 22, 23, 29, 30, 31] ROW_FMT = "{0:2d} @ {1:2d} {2}{0:<2d}"def demo(bisect_fn_):for needle in reversed(NEEDLES):position = bisect_fn_(HAYSTACK, needle) # 用特定的bisect函數來計算元素應該出現的位置offset = position * " |" # 利用該位置計算出需要幾個分割符號print(ROW_FMT.format(needle, position, offset)) # 把元素和其應該出現的位置打印出來def grade(score, breakpoints=None, grades='FDCBA'):# 講分數與評級對應起來 60以下F,90以上Abreakpoints = [60, 70, 80, 90] if not breakpoints else breakpointsi = bisect.bisect(breakpoints, score)return grades[i]用bisect.insort插入新的元素
排序很耗時,因此在得到一個有序序列之后,我們最好能夠保持它的有序.bisect.insort就是為了這個而存在的
insort(seq, item)把變量item插入到序列seq中,并能保持seq的升序順序.
import random SIZE = 7 random.seed(1729) my_list = [] for i in range(SIZE):new_item = random.randrange(SIZE*2)bisect.insort(my_list, new_item)print('%2d ->' % new_item, my_list)"""10 -> [10]0 -> [0, 10]6 -> [0, 6, 10]8 -> [0, 6, 8, 10]7 -> [0, 6, 7, 8, 10]2 -> [0, 2, 6, 7, 8, 10]10 -> [0, 2, 6, 7, 8, 10, 10]"""if __name__ == '__main__':if sys.argv[-1] == 'left': # 根據命令行上最后一個參數來選用bisect函數bisect_fn = bisect.bisect_leftelse:bisect_fn = bisect.bisectprint('DEMO:', bisect_fn.__name__) # 把選定的函數在抬頭打印出來print('haystack ->', ' '.join('%2d' % n for n in HAYSTACK))demo(bisect_fn)"""DEMO: bisecthaystack -> 1 4 5 6 8 12 15 20 21 23 23 26 29 3031 @ 14 | | | | | | | | | | | | | |3130 @ 14 | | | | | | | | | | | | | |3029 @ 13 | | | | | | | | | | | | |2923 @ 11 | | | | | | | | | | |2322 @ 9 | | | | | | | | |2210 @ 5 | | | | |108 @ 5 | | | | |8 5 @ 3 | | |5 2 @ 1 |2 1 @ 1 |1 0 @ 0 0 """print([grade(score) for score in [33, 99, 77, 70, 89, 90, 100]])總結
以上是生活随笔為你收集整理的Python 中list.sort和sorted以及bisect的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python里的dict和set的背后小
- 下一篇: 在Python中为什么切片要忽略最后一个