排序 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 是相当快;搜索普通的数组效率很低
====================================================================