collections的使用

collections的使用

二月 10, 2020

Introduction:

首先,我得介绍一下这个是个什么东西.
collections是Python的一个内建的一个集合模块,提供了许多有用的集合类

这里介绍一些我喜欢用的几个.


namedtuple

由常识可知,在Python中,tuple可以表示不变集合.
举个例子,我需要表示一个坐标,那么我们可以
> p = (1, 2)
但是看到这个(1, 2),又有谁会知道,这个tuple是表示一个坐标的呢?
但是单独的定义一个类又太麻烦,所以这个时候我们就可以利用namedtuple

1
namedtuple(typename: str, field_names: Union[str, Iterable[str]], *, verbose: bool=..., rename: bool=..., module: Optional[str]=...) -> Type[tuple]

这个是namedtuple后面的参数列表
Exp.

1
2
3
4
5
from collections import namedtuple

point = namedtuple("point", ["x", "y"])
p = point(1, 2)
print(p.x, p.y)

此时会输出

1
2
1
2

其中,我们需要知道的是,namedtuple是tuple的一个子类.
就是说,此时的p不仅是tuple,也是namedtuple

但是肯定有人会问,这样有什么好处?
好处那肯定是有的,它可以规定一个固定的输入格式.
所以我们可以定义一个数据类型,它既可以使用tuple的不可变的特性,又可以根据属性来引用.方便


deque

Python中自带的数据结构中,有一种叫做list.
list这个东西好啊,但是它存在几个非常重要的缺点.
由于list是一种线性存储的结构,这就导致其根据索引找元素的时候会非常快,但是在插入和删除元素的时候就会很慢.当数据量大的时候,效率会很低.
为了解决这个问题,我们引入deque,双向队列.
它适合用作队列和栈.

1
2
3
4
5
from collections import deque

q = deque(['a', 'b', 'c'])
q.append("x")
q.appendleft("y")

此时的输出是
['y', 'a', 'b', 'c', 'x']
不仅有appendappendleft,相同的肯定还有poppopleft
使用起来肯定很舒服


OrderedDict

Python中自带的一个数据结构叫dict字典,其构成是键值对.
但是再用dict做迭代的时候,我们没法确定key的顺序.
但是使用OrderedDict时,就可以使之排序.
具体的不多说,直接看例子

1
2
3
4
5
6
7
8
9
from collections import OrderedDict

dict = {"a":1, "c":3, "b":4}
print(dict)
>>> {"a":1, "c":3, "b":4}

orderdict = OrderedDict({"a":1, "c":3, "b":4})
print(orderdict)
>>> {"a":1, "b":4, "c":3}

由此可见,我们是根据Key排序的.这点很重要

  • Notice
    OrderedDictKey的插入会按照插入的顺序排列,而不是key本身
    Exp
    1
    2
    3
    4
    5
    6
    7
    8
    from collections import OrderedDict

    d = OrderedDict()
    d["z"] = 1
    d["y"] = 2
    d["x"] = 3
    print(d)
    >>> OrderedDict([('z', 1), ('y', 2), ('x', 3)])
    于是我们可以开动脑筋,做一个非常简单的扩展,我们可以做一个FIFO的dict结构.当超过限制时,删除最早的key.

Counter

这个是我觉得最好用的东西,没有之一.
字面意思,这就是一个计数器.计数器肯定是用来计数的.
直接看一个例子吧!
Exp

1
2
3
4
5
6
from collections import Counter

a = "kashfkehgkashfdkjsewhtrkljsdhfkjsdfhksjd"
a_c = Counter(a)
print(a_c)
>>> Counter({'k': 7, 's': 6, 'h': 6, 'f': 4, 'd': 4, 'j': 4, 'a': 2, 'e': 2, 'g': 1, 'w': 1, 't': 1, 'r': 1, 'l': 1})

可以看出来,返回的是一个字典,里面有这个字符串所有字母存在的个数.

这个可以给大家举一个例题:


你正在和你的朋友玩 猜数字(Bulls and Cows)游戏:你写下一个数字让你的朋友猜。每次他猜测后
,你给他一个提示,告诉他有多少位数字和确切位置都猜对了(称为“Bulls”, 公牛),
有多少位数字猜对了但是位置不对(称为“Cows”, 奶牛)。你的朋友将会根据提示继续猜,直到猜出秘密数字。

请写出一个根据秘密数字和朋友的猜测数返回提示的函数,用 A 表示公牛,用 B 表示奶牛。

请注意秘密数字和朋友的猜测数都可能含有重复数字。

示例 1:

输入: secret = “1807”, guess = “7810”

输出: “1A3B”

解释: 1 公牛和 3 奶牛。公牛是 8,奶牛是 0, 1 和 7。
示例 2:

输入: secret = “1123”, guess = “0111”

输出: “1A1B”

解释: 朋友猜测数中的第一个 1 是公牛,第二个或第三个 1 可被视为奶牛。
说明: 你可以假设秘密数字和朋友的猜测数都只包含数字,并且它们的长度永远相等。

来源:力扣(LeetCode)
链接:题目链接: https://leetcode-cn.com/problems/bulls-and-cows
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

1
2
3
4
5
6
7
8
class Solution:
def getHint(self, secret: str, guess: str) -> str:
from collections import Counter
secret_c = Counter(secret)
guess_c = Counter(guess)
count_A = sum((i == j for i, j in zip(secret, guess)))
count_B = sum((secret_c & guess_c).values()) - count_A
return "{}A{}B".format(count_A, count_B)