利用Python进行数据分析_01_内建数据结构、函数及文件(2)

1.1.2 列表

与元组不同,列表的长度是可变的,内容也是可以修改的。可以使用中括号[ ]或者list函数来定义列表:

In [30]: a_list = [2, 3, 7, None]

In [31]: tup = ('foo', 'bar', 'baz')

In [32]: b_list = list(tup)

In [33]: b_list
Out[33]: ['foo', 'bar', 'baz']

  In [34]: b_list[1] = 'peekaboo'

  In [35]: b_list
  Out[35]: ['foo', 'peekaboo', 'baz']

列表与元组非常相似,它们的很多函数用法都是相似的。

list函数在数据处理中常用于将迭代器或者生成器转化为列表。

In [36]: gen = range(10)

In [37]: gen
Out[37]: range(0, 10)

In [38]: list(gen)
Out[38]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

1.1.2.1 增加和移除元素

使用append方法可以将元素添加到列表的尾部:

In [39]: b_list.append('dwarf')

In [40]: b_list
Out[40]: ['foo', 'peekaboo', 'baz', 'dwarf']

使用insert方法可以将元素插入到指定的列表位置:

In [41]: b_list.insert(1, 'red')

In [42]: b_list
Out[42]: ['foo', 'red', 'peekaboo', 'baz', 'dwarf']

insert与append相比,计算代价更高。因为子序列元素不得不在内部移动为新元素提供空间。

insert的反操作是pop,该操作将特性位置的元素移除并返回:

In [43]: b_list.pop(2)
Out[43]: 'peekaboo'

In [44]: b_list
Out[44]: ['foo', 'red', 'baz', 'dwarf']

元素可以通过remove的方法移除,该方法会定位第一个符合要求的值并移除它:

In [45]: b_list.append('foo')

In [46]: b_list
Out[46]: ['foo', 'red', 'baz', 'dwarf', 'foo']

In [47]: b_list.remove('foo')

In [48]: b_list
Out[48]: ['red', 'baz', 'dwarf', 'foo']

使用in关键字可以检查一个值是否在列表中,not关键字可以用作in的反义词,表示不在

In [49]: 'dwarf' in b_list
Out[49]: True

In [50]: 'dwarf' not in b_list
Out[50]: False

1.1.2.2 连接和联合列表

与元组类似,两个列表可以使用 + 连接:

 

In [51]: [4, None, 'foo'] + [7, 8, (2,3)]
Out[51]: [4, None, 'foo', 7, 8, (2, 3)]

可以用extend方法来向已有列表添加多个元素

In [52]: x = [4, None, 'foo']

In [53]: x.extend([7, 8, (2,3)])

In [54]: x
Out[54]: [4, None, 'foo', 7, 8, (2, 3)]

通过添加内容来连接列表是一种相对高代价的操作,因为连接过程中创建了新列表,还要复制对象。使用extend将元素添加到已经存在的列表是更好的方式,尤其是在需要构建一个大型列表的时候。

 

everything = []

for chunk in list_of_lists:

    everything.extend(chunk) 

1.1.2.3 排序

可以调用列表的sort方法对列表内部进行排序(无须新建一个对象)

In [55]: a = [7, 8, 2, 5, 3]

In [56]: a.sort()

In [57]: a
Out[57]: [2, 3, 5, 7, 8]

可以通过字符串的长度进行排序:

In [58]: b = ['saw', 'small', 'He', 'foxes', 'six']

In [59]: b.sort(key = len)

In [60]: b
Out[60]: ['He', 'saw', 'six', 'small', 'foxes']

1.1.2.4 二分搜索和以排序列表的维护

内建的bisect模块实现了二分搜索和已排序列表的插值。bisect.bisect会找到元素应当被插入的位置,并保持序列排序,而bisect.insort将元素插入到相应位置

In [61]: import bisect

In [62]: c = [1, 2, 2, 2, 2, 3, 4, 7]

In [63]: bisect.bisect(c, 2)
Out[63]: 5

In [64]: bisect.bisect(c, 5)
Out[64]: 7

In [65]: bisect.insort(c, 6)

In [66]: c
Out[66]: [1, 2, 2, 2, 2, 3, 4, 6, 7]

1.1.2.5 切片

使用切片符号可以对大多数序列类型选取其子集,它的基本形式是将start:stop传入到索引符号[ ]中

In [67]: seq = [7, 2, 3, 7, 5, 6, 0, 1]

In [68]: seq[1:5]
Out[68]: [2, 3, 7, 5]

切片还可以将序列赋值给变量

In [69]: seq[3:4] = [6, 3]

In [70]: seq
Out[70]: [7, 2, 3, 6, 3, 5, 6, 0, 1]

由于起始位置start的索引是包含的,而结束位置的stop的索引并不会包含,因此元素的数量是stop-start.

start和stop是可以省略的,如果省略的话会默认传入序列的起始位置或结束位置。

In [75]: seq[:5]
Out[75]: [7, 2, 3, 6, 3]

In [76]: seq[3:]
Out[76]: [6, 3, 5, 6, 0, 1]

负索引可以从序列的尾部进行索引

In [77]: seq[-4:]
Out[77]: [5, 6, 0, 1]

In [78]: seq[-6:-2]
Out[78]: [6, 3, 5, 6]

步进值step可以在第二个冒号后面使用,意思是每隔多少个数取一个值

In [79]: seq[::2]
Out[79]: [7, 3, 3, 6, 1]

当需要对列表或元组进行翻转时,一种很聪明的用法就是向步进传值-1

In [80]: seq[::-1]
Out[80]: [1, 0, 6, 5, 3, 6, 3, 2, 7]

1.1.3 内建序列函数

1.1.3.1 enumerate

我们经常需要在遍历一个序列的同时追踪当前元素的索引,一种自行实现的方法如下

i = 0
for value in collection:
    # 使用值做点事
    i += 1

由于这种场景很常见,所以python内建了enumerate函数,返回了(i, value)的序列,其中value是元素的值, i是元素的索引。

for i, value in enumerate(collection):
    # 使用值做点事情

当需要对数据建立索引时,一种有效的模式就是使用enumerate构造一个字典,将序列值映射到索引位置上。

In [86]: some_list = ['foo', 'bar', 'baz']

In [87]: mapping = {}

In [88]: for i, v in enumerate(some_list):
    ...:     mapping[v] = i

In [89]: mapping
Out[89]: {'foo': 0, 'bar': 1, 'baz': 2}

1.1.3.2 sorted

sorted函数返回一个根据任意序列中的元素新建的已排序列表:

In [90]: sorted([7, 1, 3, 4, 9, 3, 2])
Out[90]: [1, 2, 3, 3, 4, 7, 9]

In [91]: sorted('horse race')
Out[91]: [' ', 'a', 'c', 'e', 'e', 'h', 'o', 'r', 'r', 's']

sorted函数接受的参数与列表的sort方法一致

1.1.3.3 zip

zip将列表、元组或其他序列的元素配对,新建一个元组构成的列表

In [92]: seq1 = ['foo', 'bar', 'baz']

In [93]: seq2 = ['one', 'two', 'three']

In [94]: zipped = zip(seq1, seq2)

In [95]: zipped
Out[95]: <zip at 0x244e602ae48>

In [96]: list(zipped)
Out[96]: [('foo', 'one'), ('bar', 'two'), ('baz', 'three')]

zip 可以处理任意长度的序列,它生成的列表长度由最短的序列决定

In [97]: seq3 = [False, True]

In [98]: list(zip(seq1, seq2, seq3))
Out[98]: [('foo', 'one', False), ('bar', 'two', True)]

zip的常用场景为同时遍历多个序列,有时会和enumerate同时使用

In [99]: for i, (a,b) in enumerate(zip(seq1, seq2)):
    ...:     print('{0}: {1}, {2}'.format(i, a, b))
    ...:
0: foo, one
1: bar, two
2: baz, three

给定一个已“配对”的序列时,zip函数有一种机智的方式去拆分序列。这种方式的另一种思路就是将行的列表转换为列的列表

In [100]: pitchers = [('Nolan', 'Ryan'), ('Roger', 'Clemens'), ('Schilling', 'Curt')]

In [101]: first_names, last_names = zip(*pitchers)

In [102]: first_names
Out[102]: ('Nolan', 'Roger', 'Schilling')

In [103]: last_names
Out[103]: ('Ryan', 'Clemens', 'Curt')

1.1.3.4 reversed

reversed函数将序列的元素倒序排列

In [107]: list(reversed(range(10)))
Out[107]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0

reversed是一个生成器,如果没有实例化(如使用list函数或进行for循环)的时候,它并不会产生一个倒序的列表。

 

posted on 2019-06-02 21:44  孙大仙儿的编程之路  阅读(152)  评论(0编辑  收藏  举报