[PY3]——求TopN/BtmN 和 排序问题的解决

需求

K长的序列,求TopN
K长的序列,求BtmN
排序问题

解决

  • heap.nlargest()、heap.nsmallest( )
  • sorted( )+切片
  • max( )、min( )

总结和比较

1)在Top N问题中,如果 N=1,则直接用max(iterable)/min(iterable) 即可(效率最高)。

2)如果N很大,接近集合元素,则为了提高效率,采用 sort+切片 的效率会更高,如:

 求最大的N个元素:sorted(iterable, key=key, reverse=True)[:N]

 求最小的N个元素:sorted(iterable, key=key)[:N]

3)当要查找的元素个数相对比较小的时候,使用 nlargest() 和 nsmallest() 是很合适的

详解max( )/min( )函数用法

  • 求简单的序列TopN/BtmN(N=1)问题
    lst=[1,2,3,4,5]
    print(max(lst))
    5
  • 通过key属性的使用,设置函数条件为判断的标准
    a=[-9,-8,1,3,-4,6]
    print(max(a,key=lambda x:abs(x)))
    -9
  • 找出字典中值最大的那组数据
    prices = {
    'A':123,
    'B':450.1,
    'C':12,
    'E':444,
    }
    //在对字典进行数据操作的时候,默认只会处理key,而不是value
    //先使用zip把字典的keys和values翻转过来,再用max取出值最大的那组数据
    max_prices=max(zip(prices.values(),prices.keys()))
    print(max_prices)
    (450.1, 'B')

nlargest( )/nsmallest( )详解

  • nlargest(n,iterable) 求序列iterable中的TopN | nsmallest(n,iterable) 求序列iterable中的BtmN
    import heapq
    nums=[16,7,3,20,17,8,-1]
    print(heapq.nlargest(3,nums))
    print(heapq.nsmallest(3,nums))
    [20, 17, 16]
    [-1, 3, 7]
  • nlargest(n, iterable, key=lambda) | nsmallest(n, iterable, key=lambda) key接受关键字参数,用于更复杂的数据结构中
    def print_price(dirt):
    for i in dirt:
    for x,y in i.items():
    if x=='price':
    print(x,y)
    portfolio = [
    {'name': 'IBM', 'shares': 100, 'price': 91.1},
    {'name': 'AAPL', 'shares': 50, 'price': 543.22},
    {'name': 'FB', 'shares': 200, 'price': 21.09},
    {'name': 'HPQ', 'shares': 35, 'price': 31.75},
    {'name': 'YHOO', 'shares': 45, 'price': 16.35},
    {'name': 'ACME', 'shares': 75, 'price': 115.65}]
    cheap=heapq.nsmallest(3,portfolio,key=lambda x:x['price'])
    expensive=heapq.nlargest(3,portfolio,key=lambda y:y['price'])
    print_price(cheap)
    print_price(expensive)
    price 16.35
    price 21.09
    price 31.75
    price 543.22
    price 115.65
    price 91.1

sorted( )详解

  • sorted(iterable, key=None, reverse=False)
  • reverse=True 逆序
    nums=[16,7,3,20,17,8,-1]
    print(sorted(nums))
    print(sorted(nums,reverse=True))
    [-1, 3, 7, 8, 16, 17, 20]
    [20, 17, 16, 8, 7, 3, -1]
    str=['b','a','A','s']
    print(sorted(str))
    print(sorted(str,reverse=True))
    ['A', 'a', 'b', 's']
    ['s', 'b', 'a', 'A']
  • key接受一个函数,且是个只接受一个元素的函数
  • 多条件的key应该怎么写?
    //按长度排序
    L = [{1:5,3:4},{1:3,6:3},{1:1,2:4,5:6},{1:9}]
    print(sorted(L,key=lambda x: len(x)))
    [{1: 9}, {1: 5, 3: 4}, {1: 3, 6: 3}, {1: 1, 2: 4, 5: 6}]
    //根据指定的值来排序(例如字典中的某个key)
    L = [
    ('john', 'A', 15),
    ('jane', 'B', 10),
    ('dave', 'B', 12),]
    print(sorted(L,key=lambda x:x[2],reverse=True))
    [('john', 'A', 15), ('dave', 'B', 12), ('jane', 'B', 10)]
    portfolio = [
    {'name': 'IBM', 'shares': 100, 'price': 91.1},
    {'name': 'AAPL', 'shares': 50, 'price': 543.22},
    {'name': 'FB', 'shares': 200, 'price': 21.09},
    {'name': 'HPQ', 'shares': 35, 'price': 31.75},
    {'name': 'YHOO', 'shares': 45, 'price': 16.35},
    {'name': 'ACME', 'shares': 75, 'price': 115.65}]
    print(sorted(portfolio,key=lambda x:x['price']))
    [{'shares': 45, 'name': 'YHOO', 'price': 16.35}, {'shares': 200, 'name': 'FB', 'price': 21.09}, {'shares': 35, 'name': 'HPQ', 'price': 31.75}, {'shares': 100, 'name': 'IBM', 'price': 91.1}, {'shares': 75, 'name': 'ACME', 'price': 115.65}, {'shares': 50, 'name': 'AAPL', 'price': 543.22}]
    //不规则字符串,按“小写-大写-奇数-偶数”顺序排序
    s = 'asdf234GDSdsf23'
    print("".join(sorted(s, key=lambda x: (x.isdigit(),x.isdigit() and int(x) % 2 == 0,x.isupper(),x))))
    addffssDGS33224
    //一道面试题:要求:正数在前负数在后 2.整数从小到大 3.负数从大到小
    list1=[7, -8, 5, 4, 0, -2, -5]
    print(sorted(list1,key=lambda x:(x<0,abs(x))))
    [0, 4, 5, 7, -2, -5, -8]
  • 用operator中的函数加快速度和进行多级排序
    from operator import itemgetter, attrgetter
    暂不讨论

比较三种方法的效率

  • 只求TopN=1/BtmN=1时,比较max( )和nlargest( )两种效率
    In [8]: nums=random.sample(range(1,10000),999)
    In [9]: print(max(nums))
    9999
    In [10]: %time
    CPU times: user 0 ns, sys: 0 ns, total: 0 ns
    Wall time: 13.1 µs
    In [11]: heapq.nlargest(1,nums)
    Out[11]: [9999]
    In [12]: %time
    CPU times: user 0 ns, sys: 0 ns, total: 0 ns
    Wall time: 14.1 µs
  • 当K为10,N为9(即N无限接近K时),比较了sorted( )+切片和nlargest( )两种方法的效率
    In [23]: nums=random.sample(range(1,10000),10)
    In [24]: sorted(nums,reverse=True)[:9]
    Out[24]: [8814, 7551, 7318, 5597, 5257, 4437, 4211, 2776, 2440]
    In [25]: %time
    CPU times: user 0 ns, sys: 0 ns, total: 0 ns
    Wall time: 11.4 µs
    In [26]: heapq.nlargest(9,nums)
    Out[26]: [8814, 7551, 7318, 5597, 5257, 4437, 4211, 2776, 2440]
    In [27]: %time
    CPU times: user 0 ns, sys: 0 ns, total: 0 ns
    Wall time: 154 µs
  • 当N较小时,比较了nlargest( )和sorted( )+切片两种方法

    In [18]: nums=[16,7,3,20,17,8,-1]
    In [19]: heapq.nlargest(3,nums)
    Out[19]: [20, 17, 16]
    In [20]: %time
    CPU times: user 0 ns, sys: 0 ns, total: 0 ns
    Wall time: 4.05 µs
    In [21]: sorted(nums,reverse=True)[:3]
    Out[21]: [20, 17, 16]
    In [22]: %time
    CPU times: user 0 ns, sys: 0 ns, total: 0 ns
    Wall time: 5.48 µs

    以上代码用到的import和show_tree( )

    import math
    import io
    from io import StringIO
    import heapq
    import random
    import time
    from functools import wraps
    def show_tree(tree, total_width=36, fill=' '):
    output =io.StringIO() #创建stringio对象
    last_row = -1
    for i, n in enumerate(tree): #
    if i:
    row = int(math.floor(math.log(i+1, 2)))
    else:
    row = 0
    if row != last_row:
    output.write('\n')
    columns = 2**row
    col_width = int(math.floor((total_width * 1.0) / columns))
    output.write(str(n).center(col_width, fill))
    last_row = row
    print(output.getvalue())
    print('-' * total_width)
    print(' ')
    return

    参考资料
    python3-cookbook-1.4-查找最大或最小元素
    详解Python中heapq模块的用法(这里有实现show_tree的函数代码)
    理解堆和堆排序的文章1
    理解堆和堆排序的文章2
    理解堆和堆排序的文章3
    python奇技淫巧——max/min函数的用法

转载于:https://www.cnblogs.com/snsdzjlz320/p/7133479.html

你可能感兴趣的:(python,数据结构与算法)