盘点下那些好用的py库函数| Python 主题月

本文正在参加「Python主题月」,详情查看 活动连接java

前言

不少人对py的印象就是三方库多,能直接调的函数多,这样代码总体显得很短。python

本文盘点下那些好用的内置库函数,用的好将会很是省事,配合leetcode食用更佳。git

image.png

collections

这个模块实现了特定目标的容器,以提供Python标准内建容器 dict,list , set, 和 tuple 的替代选择。api

Counter

方便的计数器,注意首字母要大写,是Counter。一般状况下,若是咱们要对一组元素统计,得新建一个空对象,而后for循环遍历元素,这就写了至少5行了吧。使用Counter,轻松搞定。就像这样数组

>>> import collections
>>> c = collections.Counter([3,1,2,3,1,4,4,4])
>>> c
Counter({4: 3, 3: 2, 1: 2, 2: 1})
>>> c[4] // 直接访问4出现的次数
3
复制代码

Counter可接受的参数能够是iterable 或者mapping,例如:缓存

>>> from collections import Counter
>>> c = Counter('gallahad') //接受字符串,可迭代类型  
>>> c
Counter({'a': 3, 'l': 2, 'g': 1, 'h': 1, 'd': 1})

>>> c = Counter({'red': 4, 'blue': 2}  //接受一个映射
复制代码

当访问Counter中不存在的键时,会返回0,很是合理。markdown

Counter对象可使用字典的方法。还有most_common()方法,能够直接指定求出现频率最高的n个元素。数据结构

顺带一提,就是传入的参数n大于了整个计数长度也不会报错,app

>>> Counter('abracadabra').most_common(3)
[('a', 5), ('b', 2), ('r', 2)]
复制代码

subtract(iterable or mapping) 一个计数器减去另一个,值还会出现负数和0函数

update(iterable or mapping),与上一个相反,是相加。

>>> c = Counter(a=4, b=2, c=0, d=-2)
>>> d = Counter(a=1, b=2, c=3, d=4)
>>> c.subtract(d)
>>> c  //c计数中减去d,c变了
Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})
复制代码

最离谱的是,还能够直接用数学运算符,包括+ - | &。

4854990846_38861117307_45f0edaa98d49e4c.jpg

c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
c + d                       # 叠加
Counter({'a': 4, 'b': 3})
c - d                       # 相减
Counter({'a': 2})
c & d                       # 与,取小
Counter({'a': 1, 'b': 1})
c | d                       # 或: 取大,以上均过滤掉了值为负数和0的项
Counter({'a': 3, 'b': 2})
复制代码

leetcode实战: 1207.独一无二的出现次数

给你一个整数数组 arr,请你帮忙统计数组中每一个数的出现次数。

若是每一个数的出现次数都是独一无二的,就返回 true;不然返回 false

解析:这题若是直接使用Counter来,有点不讲武德。2行搞定。

class Solution:
    def uniqueOccurrences(self, arr: List[int]) -> bool:
        c=collections.Counter(arr)
        return len(c)==len(set(c.values()))
复制代码

deque

双端队列,从双端添加和删除元素都是o(1)复杂度,比list快,list在头部插入和删除复杂度为o(n)。

除了能使list的方法外,还有

appendleft(x) //添加x到左端
popleft()// 移除并返回左侧第一个元素
rotate(n=1)  //
...
向右循环移动 n 步。 若是 n 是负数,就向左循环。
若是deque不是空的,向右循环移动一步就等价于 d.appendleft(d.pop()) , 向左循环一步就等价于 d.append(d.popleft()) 。
...
复制代码

maxlen定义了队列最大长度,你能够在初始化时使用参数指定最大长度,这样队列能够造成一个自然的保存最近使用记录的一个数据结构。

collections.deque([iterable[, maxlen]])

>>> from collections import deque
>>> d = deque([1,2,3],4) //初始化
>>> d
deque([1, 2, 3], maxlen=4)
>>> d.appendleft(4)  //左侧加入
>>> d
deque([4, 1, 2, 3], maxlen=4)
>>> d[0]
4
>>> d.append(5)  //右侧加入,元素个数超过最大,左侧元素自动排出了。
>>> d
deque([1, 2, 3, 5], maxlen=4)
>>> d.popleft()  //左侧排出元素
1
>>> d
deque([2, 3, 5], maxlen=4)
复制代码

实战:leetcode 3.无重复字符的最长字串

题目:给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

解析:此题是经典滑动窗口问题。

可使用双端队列deque,模拟滑动窗口。当遇到队列中已存在的字符时,从队列左侧排除元素,直到排出到与该字符相同的字符中止,记录一下次时的队列长度与max比较。该方法很是直观,仍是很好理解的,不过速度并非最快的。

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        queue = collections.deque()
        if not s:return 0
        res = 1
        for s1 in s:
            if s1 in queue:
                res = max(res,len(queue)) //更新res
                while True:
                    if queue.popleft() == s1: //左侧出队,直到无重复
                        break
            queue.append(s1) //右侧进队
        res = max(res,len(queue))
        return res
复制代码

deque很是实用的,还有102题二叉树的层次遍历,103二叉树锯齿层次遍历 ,127单词接龙,144,LRU缓存机制。 调函数就是这么义正词严。

image.png

defaultdict

使用collections.defaultdict([default_factory[, ...]])

返回一种相似字典的对象,而且该对象的值为指定类型。

一般就是设置为defaultdict(int)或者defaultdict(list),前者默认为0,后者为[].

>>> s = 'mississippi'
>>> d = defaultdict(int) //等于指定默认键值为0
>>> for k in s:
	d[k]+=1  //省去判断d中不存在键的过程

>>> d
defaultdict(<class 'int'>, {'m': 1, 'i': 4, 's': 4, 'p': 2})
复制代码

OrderedDict

有序字典,3.5之前,普通字典中键是无序的,在迭代时容易出问题。

不过3.6以后就有序了,跟js,java中的map相似了,彷佛用不上这个OrderedDict了

image.png

namedtuple

命名空间,命名元组,赋予每一个位置一个含义,提供可读性和自文档性。它们能够用于任何普通元组,并添加了经过名字获取值的能力,经过索引值也是能够的。

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11,22)
>>> p
Point(x=11, y=22)
>>> p[0]+p[1]
33
>>> p.x+p.y  //支持两种访问方式
33
复制代码

好吧,有点像c语言中的结构体struct。

itertools

神级迭代器,你能想到的都有。

accumulate

传入一个iterable,一个算数操做,默认加法即累加器,返回一个迭代器。

>>> from itertools import accumulate
>>> accumulate([1,2,3,4])  //返回的是迭代器
<itertools.accumulate object at 0x000001DFD2BDFEC0>
>>> list(accumulate([1,2,3,4]))  //累加,转为list
[1, 3, 6, 10]
>>> list(accumulate([1,3,2,4,6,5], max))  //当前最大值
[1, 3, 3, 4, 6, 6]
>>> import operator
>>> list(accumulate([1,3,2,4,6,5], operator.mul)) //乘法,求累积
[1, 3, 6, 24, 144, 720]
复制代码

chain

顾名思义,将多个可迭代的东西,有序地连起来。不用写多个循环了。

>>> list(itertools.chain('abc','efg','hij'))
['a', 'b', 'c', 'e', 'f', 'g', 'h', 'i', 'j']
复制代码

combinations

求组合的效果,跟真实的组合不一样之处在于,值相同的元素会被视为不一样,所以会出现重复。

4854990846_38861187905_20c87439172051b4.jpg

itertools.combinations(iterable, r)

>>> list(itertools.combinations('ABCD',2)) // 返回的是元组
[('A', 'B'), ('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('C', 'D')]
>>> list(itertools.combinations('dcba',2)) //出现顺序跟序列顺序有关
[('d', 'c'), ('d', 'b'), ('d', 'a'), ('c', 'b'), ('c', 'a'), ('b', 'a')]
>>> list(itertools.combinations(range(4),3))
[(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)]
复制代码

顺便提一个math.comb() 求组合的值,

>>> import math
>>> math.comb(10,2) // C(10,2)==10*9/2==45
45
复制代码

permutations

全排列。使用itertools.``permutations(iterable, r=None)

>>> from itertools import permutations
>>> list(permutations('DCBA', 2)) // 顺序与参数序列有关
[('D', 'C'), ('D', 'B'), ('D', 'A'), ('C', 'D'), ('C', 'B'), ('C', 'A'), ('B', 'D'), ('B', 'C'), ('B', 'A'), ('A', 'D'), ('A', 'C'), ('A', 'B')]
>>> list(permutations(range(3))) //第二参数默认最长
[(0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
复制代码

实战:leetcode 46全排列,39组合总数。

实际上直接调库就失去了刷题自己的意义了,不推荐使用。

product

返回笛卡尔坐标。

itertools.product(*iterables, repeat=1)

>>> list(itertools.product('abc',range(2)))
[('a', 0), ('a', 1), ('b', 0), ('b', 1), ('c', 0), ('c', 1)]
复制代码

实战 : leetcode 17.电话号码的字母组合

题:给定一个仅包含数字 2-9 的字符串,返回全部它能表示的字母组合。答案能够按 任意顺序 返回。

解法:其实就是拼音9建,按数字能打出的全部字母可能性. 组合问题,递归,回溯均可以。

使用itertools.product来作,可读性不是很好,但很短。

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        b = {"2":"abc", "3":"def", "4":"ghi", "5":"jkl", "6":"mno", "7":"pqrs", "8":"tuv", "9":"wxyz"}
        return [] if digits == "" else [ "".join(x) for x in itertools.product(*(b[d] for d in digits ))]
复制代码

zip_longest

建立一个迭代器,从每一个可迭代对象中收集元素。若是可迭代对象的长度未对齐,将根据 fillvalue 填充缺失值。迭代持续到耗光最长的可迭代对象。

itertools.zip_longest(*iterables, fillvalue=None)

>>> list(itertools.zip_longest('ABCD', 'xy', fillvalue='0'))//可用于补齐
[('A', 'x'), ('B', 'y'), ('C', '0'), ('D', '0')]
复制代码

有个题用zip_longest贼好使的,一时找不到了,415题.字符串相加

zip 与 *

zip()聚合来自每一个可迭代对象中的元素,返回迭代器。

当所输入可迭代对象中最短的一个被耗尽时,迭代器将中止迭代。

>>> list(zip('ABCD', 'xy'))
[('A', 'x'), ('B', 'y')]
复制代码

星号 * 对可迭代对象拆包,与ES6中的...剩余运算符神似。

>>> a, *b, c = range(5) //介不是ES6的结构赋值吗
>>> b
[1, 2, 3]
>>> list(zip(*(zip('ABCD', 'xy'))))//先压,再解,再压
[('A', 'B'), ('x', 'y')]
复制代码

使用*能够直接将zip对象拆开,全部的项做为参数

这个东西很是实用,例如14.最长公共前缀

题目:编写一个函数来查找字符串数组中的最长公共前缀。不存在公共前缀,返回 ""。

输入:strs = ["flower","flow","flight"]
输出:"fl"
复制代码
class Solution:
    def longestCommonPrefix(self, strs: List[str]) -> str:
        out_str = ''
        for i in zip(*strs)://解开数组,全部项为参数再压
            if len(set(i)) == 1://等于1说明i中全部元素相同,即为公共前缀
                out_str += i[0]
            else:
                break
        return out_str
复制代码

还能够用来旋转矩阵:

image.png

>>> matric = [	[1,2,3],
		[4,5,6],
		[7,8,9]]
>>> list(zip(*matric[::-1])) //顺时针
[(7, 4, 1), 
(8, 5, 2), 
(9, 6, 3)]
>>> list(zip(*matric))[::-1]  //逆时针
[(3, 6, 9), 
(2, 5, 8), 
(1, 4, 7)]
复制代码

heapq

自带的数据结构堆

调用模式有点奇葩,我的以为蛮怪的。

image.png

import heapq
h = [3,1,2,6,5,4]
>>> heapq.heapify(h)//原地修改l为堆,啥也不返回
>>> h
[1, 3, 2, 6, 5, 4]
>>> heapq.heappop(h) // 取堆顶元素,而后自动调整
1
>>> h
[2, 3, 4, 6, 5]
>>> heapq.heappush(h,1) // 加入元素,调整
>>> h
[1, 3, 2, 6, 5, 4]
复制代码

实战:leetcode.215.寻找数组中的第k个最大元素

leetcode 剑指offer40,最小的k个数

分析:寻找最大的或者最小的k个数,均可以采用建堆的方法求解。

求最小的k个数须要大顶堆,最大的k个数须要小顶堆。

class Solution:  //40题解法
    def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
        if k == 0:
            return list()

        hp = [-x for x in arr[:k]]//取负数则求最大,建小顶堆,堆的大小取k
        heapq.heapify(hp)
        for i in range(k, len(arr)):
            if hp[0] < -arr[i]: //与堆顶元素比较,若是大于堆顶元素,则入堆 
                heapq.heappop(hp)
                heapq.heappush(hp, -arr[i]) //排出最小
        ans = [-x for x in hp] //获得最大的k个数,取负数得最小
        return ans

//来源:力扣(LeetCode)

复制代码

总结

毕生所学都在这里了,点个赞吧,球球了。

相关文章
相关标签/搜索