Top N问题在搜索引擎、推荐系统领域应用很广, 如果用我们较为常见的语言,如C、C++、Java等,代码量至少也得五行,但是用Python的话,只用一个函数就能搞定,只需引入heapq(堆队列)这个数据结构即可。今天偶然看到这个库,特意记下之。

先看一个例子:

 >>> import heapq
>>> nums = [1,8,2,23,7,-4,18,23,42,37,2]
>>> print heapq.nlargest(3, nums)
[42, 37, 23]
>>>
>>> print heapq.nsmallest(3, nums)
[-4, 1, 2]

是不是很简洁?
我们具体来看一下具体的函数定义。heapq有很多函数,最为堆,队列,可想而知,也就是那些push,pop之类的操作,详细请看官方文档:https://docs.python.org/2/library/heapq.html,在这里,我们只看Top N的两个函数,其他函数在用到的时候查看文档就好了。

1)、heapq.nlargest(n, iterable[, key])

从迭代器对象iterable中返回前n个最大的元素列表,其中关键字参数key用于匹配是字典对象的iterable,用于更复杂的数据结构中。

2)、heapq.nsmallest(n, iterable[, key])

从迭代器对象iterable中返回前n个最小的元素列表,其中关键字参数key用于匹配是字典对象的iterable,用于更复杂的数据结构中。

关于第三个参数的应用,我们来看一个例子就明白了。

 >>> 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 s: s['price'])
>>> print cheap
[{'price': 16.35, 'name': 'YHOO', 'shares': 45}, {'price': 21.09, 'name': 'FB', 'shares': 200}, {'price': 31.75, 'name': 'HPQ', 'shares': 35}]
>>> expensive = heapq.nlargest(3, portfolio, key=lambda s: s['price'])
>>> print expensive
[{'price': 543.22, 'name': 'AAPL', 'shares': 50}, {'price': 115.65, 'name': 'ACME', 'shares': 75}, {'price': 91.1, 'name': 'IBM', 'shares': 100}]
>>>

从例子中可以看出,key匹配了portfolio中关键字为‘price’的一行。
到此为止,关于如何应用heapq来求Top N问题,相比通过上面的例子讲解,已经较为熟悉了。现在有几个需要注意的地方:

1)heapq.heapify(iterable):可以将一个列表转换成heapq

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

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

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

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

 >>> nums = [1,8,2,23,7,-4,18,23,42,37,2]
>>> max(nums)
42
>>> min(nums)
-4
>>> print sorted(nums, reverse=True)[:3]
[42, 37, 23]
>>> print sorted(nums)[:3]
[-4, 1, 2]

从一个集合中查找最大最小的N个元素——Python heapq 堆数据结构的更多相关文章

  1. 从集合中查找最值得方法——max(),min(),nlargest(),nsmallest()

    从集合中查找最值得方法有很多,常用的方法有max(),min(),nlargest(),nsmallest()等. 一.max()和min() 1.1 入门用法 直接使用max(),min(),返回可 ...

  2. PHP的排列组合问题 分别从每一个集合中取出一个元素进行组合,问有多少种组合?

    首先说明这是一个数学的排列组合问题C(m,n) = m!/(n!*(m-n)!) 比如:有集合('粉色','红色','蓝色','黑色'),('38码','39码','40码'),('大号','中号') ...

  3. not(expr|ele|fn)从匹配元素的集合中删除与指定表达式匹配的元素

    not(expr|ele|fn) 概述 从匹配元素的集合中删除与指定表达式匹配的元素   参数 exprStringV1.0 一个选择器字符串.深圳dd马达 elementDOMElementV1.0 ...

  4. 从一个集合中过滤另一个集合中存在的项(类似in)

    直接贴代码出来: List<PriceMark> list = PriceMarkDAL.m_PriceMarkDAL.GetList("Erp_ProName='TLC7528 ...

  5. Linq--一个集合中查找另一个集合,需熟悉这种写法

    //获取科室与病区授权的护士信息        public List<SYS_ZGKSBQDYK> GetUserWardMapByWardCode(string wardCode)   ...

  6. NoSQLBooster如何MongoDB的部分文档从一个集合拷贝到另外一个集合中

    假设MongoDB数据库中存有collection_A和collection_B两个集合,如下图所示: (一)先从集合collection_A中拷贝选择的文档 打开collection_A,看到目前有 ...

  7. C#算法之向一个集合中插入随机不重复的100个数

    一道非常经典的C#笔试题: 需求:请使用C#将一个长度为100的int数组,插入1-100的随机数,不能重复,要求遍历次数最少. 1.最简单的办法 var rd = new Random(); Lis ...

  8. 【Aaronyang原创】用linq取出一个集合中重复的数据

    文章已经迁移:http://www.ayjs.net/2013/07/69/ 文章已经迁移:http://www.ayjs.net/2013/07/69/ 文章已经迁移:http://www.ayjs ...

  9. mysql 获取一个表中缺失的最小编号

    select count(*),t1.`name` from test_id t1INNER JOIN test_id t2on t1.id >= t2.idgroup by t1.id,t1. ...

随机推荐

  1. vue 未完待续

    1. v-text:主要用来更新textContent,可以等同于JS的text属性. <span v-text="msg"></span> 这两者等价: ...

  2. R语言-增加图例

    legend()函数 > plot(rain$Tokyo,type="l",col="red", + ylim=c(0,300), + main=&quo ...

  3. 定时任务 spring @Scheduled注解

    使用spring @Scheduled注解执行定时任务: 运行!!! 关于Cron表达式(转载) 表达式网站生成: http://cron.qqe2.com/  直接点击 cronExpression ...

  4. Netty4.0源码解析 NioServerSocketChannel

    一.引言Netty的Channel在JDK NIO的Channel基础上做了一层封装,提供了更多的功能.Netty的中的Channel实现类主要有:NioServerSocketChannel(用于服 ...

  5. @font-face使用在线字体

    @font-face规则在CSS3规范中属于字体模块,该规则的推出对于网页设计来说是一个革命性的进步.在传统设计中,设计师不敢使用各种艺术字体类型,甚至是常规字体也需要慎重使用.因为设计师必须考虑每位 ...

  6. java学习笔记(三):类和对象

     创建对象 构造器 每一个类都有一个构造器. 如果我们不单独为一个类编写构造器那么 Java 的编译器将会给这个类建立一个默认的构造器. 每当一个新的对象被创建,至少一个构造器将会被调用. 构造器的一 ...

  7. NodeJs第3方包说明

    formidable 作用:实现简单文件上传 var formidable = require('formidable'); var form = new formidable.IncomingFor ...

  8. 使用ibatis时 sql中 in 的参数赋值(转)

    转:http://www.cnblogs.com/sunzhenchao/archive/2012/12/03/2799365.html 一.问题描述: 1.在使用ibatis执行下面的sql: up ...

  9. dede织梦动态页面通过手机模板实现wap浏览

    https://jingyan.baidu.com/article/a948d6517be0eb0a2dcd2ebc.html

  10. python积累二:中文乱码解决方法

    根据网上提供的解决方法:添加#coding=utf-8或# -*- coding: utf-8 -*- #coding=utf-8 print "还不行?" 执行结果:还是乱码!: ...