python 学习汇总55:序列字典排序汇总sorted,heapq(查找最小值),bisect ,numpy.searchsorted(二分法排序)(- tcy)

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




猜你喜欢

转载自blog.csdn.net/tcy23456/article/details/84218507
今日推荐