python 學習彙總55:序列字典排序彙總sorted,heapq(查詢最小值),bisect ,numpy.searchsorted(二分法排序)(- tcy)
阿新 • • 發佈:2018-11-23
排序 sorted 建立日期:2018/6/29 修改日期:2017/11/20
1.1.函式:sorted(iterable, /, *, key= None, reverse= False)是一個高階函式
sorted函式用途:普通排序,自定義排序 heapq模組用途:獲取最小元素 bisect 模組:python二分法模組 numpy.searchsorted二分查詢的函式 bisect 模組用途:二分法排序
引數:
key是函式,實現自定義的排序
reverse=True 反向排序
區別:
列表list.sort()方法 就地修改列表
內建函式sorted() 從迭代器中構建一個新的排序列表
1.2.例項:
# 例項1:
a=[1,4,2,-3,6,5]
a.sort() #就地修改列表並返回None; 升序
sorted(a,key=abs,reverse=True) #返回一個新的排序列表; [6, 5, 4, -3, 2, 1]
# 例項2: lst=[1, 2, 3, 4, 5, 6, 7, 8, 9] sorted(lst, key=lambda x: abs(5-x)) # 按照元素與5距離從小到大進行排序[5, 4, 6, 3, 7, 2, 8, 1, 9]
# 例項3: lsts=[(13, 'A'), (14, 'A'), (11, 'D'), (11, 'F')] lsts.sort() lsts # [(11, 'D'), (11, 'F'), (13, 'A'), (14, 'A')] lsts.sort(key=lambda lst: lst[0]) lsts # [(11, 'D'), (11, 'F'), (13, 'A'), (14, 'A')] lsts.sort(key=lambda lst: lst[1]) lsts # [(13, 'A'), (14, 'A'), (11, 'D'), (11, 'F')]
# 例項4:
lsts = [(2, 103, "C"), (1, 111, "G"), (1, 103, "B"), (3, 104, "C")]
sorted(lsts) #預設按元素1排序
# [(1, 103, 'B'), (1, 111, 'G'), (2, 103, 'C'), (3, 104, 'C')]
sorted(lsts,key=lambda lst: lst[2]) #按元素3排序
# [(1, 103, 'B'), (2, 103, 'C'), (3, 104, 'C'), (1, 111, 'G')]
sorted(lsts,key=lambda lst: (lst[1], lst[2])) #先按元素2排序,再按元素3排序
sorted(lsts,key=lambda lst: lst[1:3]) #效果同上
# [(1, 103, 'B'), (2, 103, 'C'), (3, 104, 'C'), (1, 111, 'G')]
lsts.sort(key=lambda lst: (lst[2].lower(), lst[1]))#先按元素3小寫排序,再按元素2排序
# [(1, 103, 'B'), (2, 103, 'C'), (3, 104, 'C'), (1, 111, 'G')]
# 例項5:
a = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
def by_name(t):
return t[0]
s1 = sorted(a, key=by_name) #按名字排序
def by_name_score(t):
return (t[0],t[1])
s1 = sorted(a, key=by_name_score) #名字相同,按照分數排序(預設升序)
# 例項6:
class Student:
def __init__(self, name, grade, age):
self.name = name
self.grade = grade
self.age = age
def __repr__(self):
return repr((self.name, self.grade, self.age))
student_objects = [Student('Tom', 'A', 15),Student('Mark', 'B', 10),Student('John', 'B', 12)]
b=sorted(student_objects, key=lambda s=a: s.age) # sort by age用物件屬性
# 例項7:
import random
random.seed(0)
rand_list = random.sample(range(100), 8)#[49, 97, 53, 5, 33, 65, 62, 51]
sorted(rand_list) #[5, 33, 49, 51, 53, 62, 65, 97]
2. 運算子operator模組函式 更簡單和更快
from operator import itemgetter, attrgetter
student = [ ('john', 'A', 15), ('jane', 'B', 12),('dave', 'B', 10),]
sorted(student, key=itemgetter(2) , reverse=True) # sort by age
sorted(student, key=itemgetter(0,2)) #多層次排序
sorted(student_objects, key=attrgetter('grade', 'age')) #多層次排序
3.__it__
Student.__lt__ = lambda self, other: self.age < other.age
b1=sorted(student_objects)
4.字典進行排序 2018/9/13
d={'k1':2,'k6':3,'k5':4,'k2':6,'k3':3}
#例項0.sorted
sorted(d.keys()) #按key值對字典排序 # ['k1', 'k2', 'k3', 'k5', 'k6']
sorted(d.values())#按value值對字典排序 # [2, 3, 3, 4, 6]
sorted(d) # ['k1', 'k2', 'k3', 'k5', 'k6']
sorted(d.items()) # [('k1', 2), ('k2', 6), ('k3', 3), ('k5', 4), ('k6', 3)]
# 例項1.最簡單的方法,排列元素(key/value對),然後挑出值
def sortedDict(iDict):
items = sorted(iDict.items())
return [value for key, value in items]
# 例項2:使用排列鍵(key)的方式,挑出值,速度比方法1快。
def sortedDict(iDict):
keys = sorted(iDict.keys())
return [iDict[key] for key in keys]
# 例項3:通過對映的方法去更有效的執行最後一步
def sortedDict(iDict):
keys = sorted(iDict.keys())
return map(iDict.get,keys )
# 例項4.對字典按鍵排序,用元組列表的形式返回,同時使用lambda函式來進行
sorted(d.items(), key=lambda e:e[0], reverse=True)
# 按鍵排序# [('k6', 3), ('k5', 4), ('k3', 3), ('k2', 6), ('k1', 2)]
sorted(d.items(), key=lambda e:e[1], reverse=True)
# 按值排序# [('k2', 6), ('k5', 4), ('k6', 3), ('k3', 3), ('k1', 2)]
# 例項5.operator
import operator
sorted_x = sorted(d.items(), key=operator.itemgetter(0))
# 按照item中的第一個字元進行排序,即按照key排序
sorted_x # [('k1', 2), ('k2', 6), ('k3', 3), ('k5', 4), ('k6', 3)]
sorted_x = sorted(d.items(), key=operator.itemgetter(1))
# 這裡改為按照item的第二個字元排序,即value排序
sorted_x # [('k1', 2), ('k6', 3), ('k3', 3), ('k5', 4), ('k2', 6)]
heapq-堆 列表訪問最小元素 2018/11/20
==================================================================
1.用途
提供了基於常規列表實現堆的功能。
最低價值條目始終保持在零位。
重複訪問最小元素但不想執行完整列表排序的應用程式非常有用:
==================================================================
2.例項:
from heapq import heapify, heappop, heappush
data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
heapify(data) # 將列表重新排列為堆順序
heappush(data, -5) # 新增新值
[heappop(data) for i in range(3)] # 獲取三個最小值[-5, 0, 1]
===================================================================
Python 二分查詢 bisect 模組 2018/6/30
==================================================================
1.概念
列表:
# list內部實現是一個數組一個線性表。列表查詢list.index() 方法,其時間複雜度O(n)
二分查詢:
# 也稱折半查詢,演算法每一次比較都使搜尋範圍縮小一半, 時間複雜度為 O(logn)
基本原理:
# 從陣列中間元素開始,如果中間元素正好是要查詢的元素,則搜素過程結束;
# 如果某一特定元素大於或者小於中間元素,則在陣列大於或小於中間元素的那一半中查詢, 而且跟開始一樣從中間元素開始比較。
# 如果在某一步驟陣列為空,則代表找不到。
==================================================================
2.二分方法查詢
# 例項1:遞迴實現二分查詢
def binary_search_recursion(lst, value, low, high):
if high < low:
return None
mid = int((low + high) / 2 )
if lst[mid] > value:
return binary_search_recursion(lst, value, low, mid -1)
elif lst[mid] < value:
return binary_search_recursion(lst, value, mid +1, high)
else:
return mid
#例項2:
def search(sequence, number, lower=0, upper=None):
''''序列是已經排序好的'''
if upper is None:
upper = len(sequence) - 1
if lower == upper:
assert number == sequence[upper] # assert語句用來宣告某個條件是真的
return upper
else:
middle = (lower + upper) // 2
if number > sequence[middle]:
return search(sequence, number, middle + 1, upper)
else:
return search(sequence, number, lower, middle)
# 例項3:迴圈實現二分查詢
def binary_search_loop(lst ,value):
low, high = 0, len(lst ) -1
while low <= high:
mid = int((low + high) / 2 )
if lst[mid] < value:
low = mid + 1
elif lst[mid] > value:
high = mid - 1
else:
return mid
low+=1
return None
# 效能測試:
import random
lst = [random.randint(0, 10000) for i in range(100000)]
lst.sort()
def test_recursion():binary_search_recursion(lst, 999, 0, len(lst ) -1)
def test_loop():binary_search_loop(lst, 999)
import timeit
t1 = timeit.Timer("test_recursion()", setup="from __main__ import test_recursion")
t2 = timeit.Timer("test_loop()", setup="from __main__ import test_loop")
print( "Recursion:", t1.timeit())#Recursion: 10.576744321
print( "Loop:", t2.timeit() ) #Loop: 8.540910507 迴圈方式比遞迴效率高。
=====================================================================
3.bisect 模組
# 用於維護有序列表。bisect 模組實現了一個演算法用於插入元素到有序列表。
在一些情況下,這比反覆排序列表或構造一個大的列表再排序的效率更高。
Bisect 是二分法的意思,這裡使用二分法來排序,它會將一個元素插入到一個有序列表的合適位置,
這使得不需要每次呼叫 sort 的方式維護有序列表。
======================================================================
3.1.函式:
bisect.bisect_left(a ,x, lo=0, hi=len(a)) :# 查詢在有序列表a中插入x的index。
# lo 和 hi 用於指定列表的區間,預設是使用整個列表。
# 如果 x 已經存在,在其左邊插入。返回值為 index。
bisect.bisect(a, x ,lo=0, hi=len(a))
bisect.bisect_right(a ,x, lo=0, hi=len(a))# 這2個函式和 bisect_left 類似,但如果 x 已經存在,在其右邊插入。
bisect.insort_left(a ,x, lo=0, hi=len(a)) :# 在有序列表 a 中插入 x。
# 等效:a.insert(bisect.bisect_left(a ,x, lo, hi), x)
bisect.insort(a, x ,lo=0, hi=len(a))
bisect.insort_right(a ,x, lo=0, hi=len(a))
# 和 insort_left 類似,但如果 x 已經存在,在其右邊插入。
說明:
bisect* 只用於查詢 index, 不進行實際的插入;
insort* 則用於實際插入。該模組比較典型的應用是計算分數等級:
=======================================================================
# 3.2.示例1:
import bisect
import random
random.seed(1)
lst = []
for i in range(0, 6):
r = random.randint(1, 100)
position = bisect.bisect(lst, r) #右邊插入
bisect.insort(lst, r) #排序
print('%3d %3d' % (i, position),lst)
#輸出結果:
# 0 0 [18]
# 1 1 [18, 73]
# 2 2 [18, 73, 98]
# 3 0 [9, 18, 73, 98]
# 4 2 [9, 18, 33, 73, 98]
# 5 1 [9, 16, 18, 33, 73, 98]
# 3.2.例項2:典型的應用是計算分數等級
def grade(score ,lst=[60, 70, 80, 90], grades='FDCBA'):
i = bisect.bisect(lst, score)
return grades[i],i
print( [grade(score) for score in [100, 55, 77, 70, 89, 90, 65,60,80]])
#執行結果:
#[('A',4),('F',0),('C',2),('C',2),('B',3),('A',4),('D',1), ('D',1), ('B',3)]
# 3.2.例項3:用 bisect 模組實現二分查詢
def binary_search_bisect(lst, x):
from bisect import bisect_left
i = bisect_left(lst, x)
if i != len(lst) and lst[i] == x:
return i
return None
# 3.2.例項4:-列表排序
import bisect
scores = [(100, 'perl'), (200, 'tcl'), (400, 'lua'), (500, 'python')]
bisect.insort(scores, (300, 'ruby'))
scores#[(100, 'perl'), (200, 'tcl'), (300, 'ruby'), (400, 'lua'), (500, 'python')]
====================================================================
4.numpy.searchsorted二分查詢的函式
# 用法與 bisect 基本相同,如要右邊插入時,需要設定引數 side ='right'
# 例項1:
import numpy as np
from bisect import bisect_left, bisect_right
data = [2, 4, 7, 9]
bisect_left(data, 4) #1
np.searchsorted(data, 4) #1
bisect_right(data, 4) #2
np.searchsorted(data, 4, side='right') #2
# 例項2:numpy.searchsorted 可以同時搜尋多個值
np.searchsorted([1,2,3,4,5], 3) #2
np.searchsorted([1,2,3,4,5], 3, side='right') #3
np.searchsorted([1,2,3,4,5], [-10, 10, 2, 3]) #array([0, 5, 1, 2])
注意:
np.searchsorted 搜尋 np.ndarray 是相當快;搜尋普通的陣列效率很低
====================================================================