Python内嵌的集合类型有list、tuple、set、dict。
列表list:看似数组,但比数组强大,支持索引、切片、查找、增加等功能。
元组tuple:功能跟list差不多,但一旦生成,长度及元素都不可变(元素的元素还是可变),似乎就是一更轻量级、安全的list。
字典dict:键值对结构哈希表,跟哈希表的性质一样,key无序且不重复,增删改方便快捷。
set:无序且不重复的集合,就是一个只有键没有值的dict,Java的HashSet就是采用HashMap实现,但愿python不会是这样,毕竟set不需要value,省去了很多指针。
 
称之为生成器,或者列表推导式,是python中有一个特殊的数据类型,实际上并不是一个数据结构,只包括算法和暂存的状态,并且具有迭代的功能。
 
先看看它们的内存使用情况,分别用生成器生成100000个元素的set, dict, generator, tuple, list。消耗的内存dict, set, list, tuple依次减少,生成的对象大小也是一样。由于generator并不生成数据表,所以不需要消耗内存:
import sys
from memory_profiler import profile @profile
def create_data(data_size):
data_generator = (x for x in xrange(data_size))
data_set = {x for x in xrange(data_size)}
data_dict = {x:None for x in xrange(data_size)}
data_tuple = tuple(x for x in xrange(data_size))
data_list = [x for x in xrange(data_size)]
return data_set, data_dict, data_generator, data_tuple, data_list data_size = 100000
for data in create_data(data_size):
print data.__class__, sys.getsizeof(data) Line # Mem usage Increment Line Contents
================================================
4 14.6 MiB 0.0 MiB @profile
5 def create_data(data_size):
6 14.7 MiB 0.0 MiB data_generator = (x for x in xrange(data_size))
7 21.4 MiB 6.7 MiB data_set = {x for x in xrange(data_size)}
8 29.8 MiB 8.5 MiB data_dict = {x:None for x in xrange(data_size)}
9 33.4 MiB 3.6 MiB data_tuple = tuple(x for x in xrange(data_size))
10 38.2 MiB 4.8 MiB data_list = [x for x in xrange(data_size)]
11 38.2 MiB 0.0 MiB return data_set, data_dict, data_generator, data_tuple, data_list <type 'set'> 4194528
<type 'dict'> 6291728
<type 'generator'> 72
<type 'tuple'> 800048
<type 'list'> 824464

再看看查找性能,dict,set是常数查找时间(O(1)),list、tuple是线性查找时间(O(n)),用生成器生成指定大小元素的对象,用随机生成的数字去查找:

import time
import sys
import random
from memory_profiler import profile def create_data(data_size):
data_set = {x for x in xrange(data_size)}
data_dict = {x:None for x in xrange(data_size)}
data_tuple = tuple(x for x in xrange(data_size))
data_list = [x for x in xrange(data_size)]
return data_set, data_dict, data_tuple, data_list def cost_time(func):
def cost(*args, **kwargs):
start = time.time()
r = func(*args, **kwargs)
cost = time.time() - start
print 'find in %s cost time %s' % (r, cost)
return r, cost #返回数据的类型和方法执行消耗的时间
return cost @cost_time
def test_find(test_data, data):
for d in test_data:
if d in data:
pass
return data.__class__.__name__ data_size = 100
test_size = 10000000
test_data = [random.randint(0, data_size) for x in xrange(test_size)]
#print test_data
for data in create_data(data_size):
test_find(test_data, data) 输出:
----------------------------------------------
find in <type 'set'> cost time 0.47200012207
find in <type 'dict'> cost time 0.429999828339
find in <type 'tuple'> cost time 5.36500000954
find in <type 'list'> cost time 5.53399991989
100个元素的大小的集合,分别查找1000W次,差距非常明显。不过这些随机数,都是能在集合中查找得到。修改一下随机数方式,生成一半是能查找得到,一半是查找不到的。从打印信息可以看出在有一半最坏查找例子的情况下,list、tuple表现得更差了。
def randint(index, data_size):
return random.randint(0, data_size) if (x % 2) == 0 else random.randint(data_size, data_size * 2) test_data = [randint(x, data_size) for x in xrange(test_size)] 输出:
----------------------------------------------
find in <type 'set'> cost time 0.450000047684
find in <type 'dict'> cost time 0.397000074387
find in <type 'tuple'> cost time 7.83299994469
find in <type 'list'> cost time 8.27800011635

元素的个数从10增长至500,统计每次查找10W次的时间,用图拟合时间消耗的曲线,结果如下图,结果证明dict, set不管元素多少,一直都是常数查找时间,dict、tuple随着元素增长,呈现线性增长时间:

import matplotlib.pyplot as plot
from numpy import * data_size = array([x for x in xrange(10, 500, 10)])
test_size = 100000
cost_result = {}
for size in data_size:
test_data = [randint(x, size) for x in xrange(test_size)]
for data in create_data(size):
name, cost = test_find(test_data, data) #装饰器函数返回函数的执行时间
cost_result.setdefault(name, []).append(cost) plot.figure(figsize=(10, 6))
xline = data_size
for data_type, result in cost_result.items():
yline = array(result)
plot.plot(xline, yline, label=data_type) plot.ylabel('Time spend')
plot.xlabel('Find times') plot.grid() plot.legend()
plot.show()

迭代的时间,区别很微弱,dict、set要略微消耗时间多一点:

@cost_time
def test_iter(data):
for d in data:
pass
return data.__class__ .__name__ data_size = array([x for x in xrange(1, 500000, 1000)])
cost_result = {}
for size in data_size:
for data in create_data(size):
name, cost = test_iter(data)
cost_result.setdefault(name, []).append(cost) #拟合曲线图
plot.figure(figsize=(10, 6))
xline = data_size
for data_type, result in cost_result.items():
yline = array(result)
plot.plot(xline, yline, label=data_type) plot.ylabel('Time spend')
plot.xlabel('Iter times') plot.grid() plot.legend()
plot.show()

删除元素消耗时间图示如下,随机删除1000个元素,tuple类型不能删除元素,所以不做比较:

@cost_time
def test_delete(test_data, data):
for d in test_data:
data.remove(d)
return data.__class__.__name__ @cost_time
def test_dict_delete(test_data, data):
for d in test_data:
del data[d]
return data.__class__.__name__ def create_data(data_size):
data_set = {x for x in xrange(data_size)}
data_dict = {x:None for x in xrange(data_size)}
data_list = [x for x in xrange(data_size)]
return data_set, data_dict, data_list #创建随机删除数据集
def create_random_test_data(size, range_size):
test_data = set()
while(len(test_data) < size):
test_data.add(random.randint(0, range_size))
return test_data #dict没有remove方法,用del dict[key]来删除数据,其他数据类型使用remove方法
delete_method = {list: test_delete, set: test_delete, dict: test_dict_delete} #每次检测1000增量大小的数据的删除一半时间
data_size = array([x for x in xrange(1000, 20000, 1000)])
cost_result = {}
test_size = 1000
for size in data_size:
test_data = create_random_test_data(test_size, size)
for data in create_data(size):
name, cost = delete_method[type(data)](test_data, data) #返回数据类型的名字和方法的执行时间
cost_result.setdefault(name, []).append(cost)

随机删除一半的元素,图形就呈指数时间(O(n2))增长了:

添加元素消耗的时间图示如下,统计以10000为增量大小的元素个数的添加时间,都是线性增长时间,看不出有什么差别,tuple类型不能添加新的元素,所以不做比较:
@cost_time
def test_dict_add(test_data, data):
for d in test_data:
data[d] = None
return data.__class__ .__name__ @cost_time
def test_set_add(test_data, data):
for d in test_data:
data.add(d)
return data.__class__ .__name__ @cost_time
def test_list_add(test_data, data):
for d in test_data:
data.append(d)
return data.__class__ .__name__ #初始化数据,指定每种类型对应它添加元素的方法
def init_data():
test_data = {
'list': (list(), test_list_add),
'set': (set(), test_set_add),
'dict': (dict(), test_dict_add)
}
return test_data #每次检测10000增量大小的数据的添加时间
data_size = array([x for x in xrange(10000, 1000000, 10000)])
cost_result = {}
for size in data_size:
test_data = [x for x in xrange(size)]
for data_type, (data, add) in init_data().items():
name, cost = add(test_data, data) #返回方法的执行时间
cost_result.setdefault(data_type, []).append(cost) plot.figure(figsize=(10, 6))
xline = data_size
for data_type, result in cost_result.items():
yline = array(result)
plot.plot(xline, yline, label=data_type) plot.ylabel('Time spend')
plot.xlabel('Add times') plot.grid() plot.legend()
plot.show()

代码与图详解性能之Python集合类型(list tuple dict set generator)的更多相关文章

  1. 十图详解tensorflow数据读取机制(附代码)转知乎

    十图详解tensorflow数据读取机制(附代码) - 何之源的文章 - 知乎 https://zhuanlan.zhihu.com/p/27238630

  2. php调用C代码的方法详解和zend_parse_parameters函数详解

    php调用C代码的方法详解 在php程序中需要用到C代码,应该是下面两种情况: 1 已有C代码,在php程序中想直接用 2 由于php的性能问题,需要用C来实现部分功能   针对第一种情况,最合适的方 ...

  3. 【机器学习】【条件随机场CRF-2】CRF的预测算法之维特比算法(viterbi alg) 详解 + 示例讲解 + Python实现

    1.CRF的预测算法条件随机场的预测算法是给定条件随机场P(Y|X)和输入序列(观测序列)x,求条件概率最大的输出序列(标记序列)y*,即对观测序列进行标注.条件随机场的预测算法是著名的维特比算法(V ...

  4. Understand:高效代码静态分析神器详解(转)

    之前用Windows系统,一直用source insight查看代码非常方便,但是年前换到mac下面,虽说很多东西都方便了,但是却没有了静态代码分析工具,很幸运,前段时间找到一款比source ins ...

  5. 单元测试系列之四:Sonar平台中项目主要指标以及代码坏味道详解

    更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 原文链接:http://www.cnblogs.com/zishi/p/6766994.html 众所周知Sona ...

  6. Understand:高效代码静态分析神器详解(一)

    Understand:高效代码静态分析神器详解(一) Understand   之前用Windows系统,一直用source insight查看代码非常方便,但是年前换到mac下面,虽说很多东西都方便 ...

  7. Understand:高效代码静态分析神器详解(一) | 墨香博客 http://www.codemx.cn/2016/04/30/Understand01/

    Understand:高效代码静态分析神器详解(一) | 墨香博客 http://www.codemx.cn/2016/04/30/Understand01/ ===== 之前用Windows系统,一 ...

  8. UML类图详解_关联关系_一对多

    对于一对多的示例,可以想象一个账户可以多次申购.在申购的时候没有固定上限,下限为0,那么就可以使用容器类(container class)来搞,最常见的就是vector了. 下面我们来看一个“一对多” ...

  9. UML类图详解_关联关系_多对一

    首先先来明确一个概念,即多重性.什么是多重性呢?多重性是指两个对象之间的链接数目,表示法是“下限...上限”,最小数据为零(0),最大数目为没有设限(*),如果仅标示一个数目级上下限相同. 实际在UM ...

随机推荐

  1. CentOS6.5下安装JDK

    之前一直没有完全的总结出一篇关于Linux下安装Java的过程,今天正好就整理下. 下载jdk 如果在官网下载比较慢,那么可以到我的云盘分享上,下载jdk 1.8.0的版本: 下载地址参考链接 解压缩 ...

  2. MyBatis学习总结(五)——实现关联表查询

    一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...

  3. DNS正向解析与反向解析

    DNS:(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网, 而不去记住能够被机器直接读取的IP数串.通过主机名,最 ...

  4. 项目中是用eCharts

    1.首先在项目中引入echart.js库. <!DOCTYPE HTML> <%@page contentType="text/html; charset=UTF-8&qu ...

  5. Apache Tomcat

    官网:http://tomcat.apache.org/ Documentation:http://tomcat.apache.org/tomcat-8.0-doc/index.html

  6. css 用direction来改变元素水平方向,价值研究。

    "direction"有两个值:ltr | rtl ltr:从左往右 rtl:从右往左 默认:ltr 一起看个效果就懂了. <style> div{ direction ...

  7. AJAX文件上传实践与分析,带HTML5文件上传API。

    对于HTML5已经支持AJAX文件上传了,但如果需要兼容的话还是得用一点小技巧的,HTML5等等介绍,先来看看以前我们是怎么写的. 网上可能会有一些叫AJAX文件上传插件,但在AJAX2.0之前是不可 ...

  8. Js控制显示、隐藏文本框中的密码

    Js控制显示.隐藏文本框中的密码,也可称为是一款小型的JavaScript星号密码破解器,点击会显示出密码类型的文本框中的真实信息,再次点击则还原,程序 主要是获取HTML元素对象,然后强制更改元素属 ...

  9. Android入门(四)UI-创建自定义控件

    原文链接:http://www.orlion.ga/441/ 一.引入布局 iphone应用顶部会有一个标题栏,我们可以模仿着做一个,但是如果我们的程序中很多个活动都需要这样的标题栏,如果 每一个活动 ...

  10. hdu3635 Dragon Balls(带权并查集)

    /* 题意:有N个城市, 每一个城市都有一个龙珠(编号与城市的编号相同),有两个操作 T A ,B 将标号为A龙珠所在城市的所有的龙珠移动到B龙珠所在城市中! 思路:并查集 (压缩路径的时候将龙珠移动 ...