Blog Archive

Friday, February 7, 2020

lru_cache

Source:

https://medium.com/lambda-automotive/python-and-lru-cache-f812bbdcbb51


from functools import lru_cache#Option1:lru_cache(maxsize=128, typed=False)  #default: maxsize=128, non-sensitive to type
#Option2:@lru_cache(maxsize=4) 
#Option3:@lru_cache(None)  # maxsize is unlimitedWhen to use: repeated calling. No repetition, no use.
https://docs.python.org/3/library/functools.html

Virtualenv with Virtualenvwrapper on Ubuntu 18.04 [updated: 2/7/2020]

Before we start with the tutorial I would like to tell you the story how I realized that I need a reminder on how to set up virtualenvwrapper on top of virtualenv in Ubuntu 18.04. I have done this process several of times on different computers and every time it seemed to be just a little bit different than before.
Recently I got myself a new laptop and I on my way home I have read several tutorials on “How to set up virtualenvwrapper on Ubuntu 18.04”. And let me tell you that it seems really easy because all of those tutorials are pretty straight forward and basically explain how to do the next three 3 things:
  • Install virtualenv
  • Install virtualenvwrapper
  • Edit .bashrc/.bash_profile or both
But even though all these tutorials are meant to help us set up virtualenvwrapper on a modern Ubuntu 18.04 installation non of them worked for me.
I had several errors while trying to figure out what went wrong while following these tutorials. First I’ve had some of “mkvirtualenv: command not found”, then a little of “-bash: /usr/bin/virtualenvwrapper.sh: No such file or directory”, and then a touch of “ERROR: virtualenvwrapper could not find virtualenv in your path”.
After some research I realized that all virtualenvwrapper Ubuntu 18.04 tutorials are copies an old text written before April 2016 (release date of Ubuntu 16.04).
And I know it to be true because from Ubuntu 16.04 and onward the location for the vritualenvwrapper’s pip installation has changed from /usr/local/bin/virtualenvwrapper.sh to ~/.local/bin/virtualenvwrapper.sh.Note that the local directory is hidden.
So let’s start by writing a tutorial that will show you how to avoid all those issues mentioned above.

Prerequisites

In this text I will show you how to set up virtualenvwrapper with pip3 (pip for Python 3). I chosen this version of pip instead of a Python 2 version because Python’s 2 end of life is January 1. 2020.
Python 2 will retire in… https://pythonclock.org/
To complete this tutorial you will need a computer with Ubuntu 18.04 installed and a internet connection :) Also some knowledge in terminals and Vim editor would be useful. We will assume you already updated and upgraded the system.

Setting up a Virtual Environment

Now open your terminal in the home directory by right clicking and choosing the option “Open in Terminal” or you can press the CTRL, ALT, and T keys on your keyboard at the same time to open the Terminal application automatically.
You first need to create a special directory that will hold all of your virtual environments so proceed with creating a new hidden directory called virtualenv.
Now you should install pip for Python3.
Confirm the pip3 installation.
pip3 --version
Now install virtualenv via pip3.
To find out the location where your virtualenv was installed type:
Install virtualenvwrapper via pip3:
We are going to modify your .bashrc file by adding a row that will adjust every new virtual environment to use Python 3. We will point virtual environments to the directory we created above (.virtualenv) and we will also point to the locations of the virtualenv and virtualenvwrapper.
Now open the .bashrc file using Vim editor.
If you still haven’t used Vim editor or you don’t have it installed on your computer you should install it now. It is one of widely used Linux editors and for a good reason.
After you installed Vim open the file .bashrc file by typing in the vim .bashrc command in your terminal. Navigate to the bottom of the .bashrc file, press the letter i to enter the insert mode of Vim and add these rows:


#Virtualenvwrapper settings:
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
export WORKON_HOME=$HOME/.virtualenvs
export VIRTUALENVWRAPPER_VIRTUALENV=/home/goran/.local/bin/virtualenv
source ~/.local/bin/virtualenvwrapper.sh

After you are done, press the esc key then type:wq and press enter, this command will save and exit the Vim editor. Close and reopen your terminal when you’re done.
To create a virtual environment in Python3 and activate it immediately use this command in your terminal:
You should confirm that this environment is set up for Python3:
To deactivate the environment use the deactivate command.
To list all available virtual environments use the command workon or lsvirtualenv (Same result as workon but shown in a fancy way) in your terminal:
To activate one specific environment use workon + name of your environment:
There are several useful command you might need to use someday:
Rmvirtualenv will remove a specific virtual environment located in your .virtualenv directory.
Cpvirtualenv will copy the existing virtual environment to a new virtual environment and activate it.
Well done!
You have now created your first isolated Python 3 environment!
Thank you for reading! Check out more articles like this on my Medium profile: https://medium.com/@goranaviani and other fun stuff I build on my GitHub page: https://github.com/GoranAviani

Source:

Thursday, January 23, 2020

How to install ubuntu on windows 10



Ref:

https://docs.microsoft.com/en-us/windows/wsl/install-win10?redirectedfrom=MSDN

https://linuxize.com/post/how-to-install-pip-on-ubuntu-18.04/

Step 1:
Before installing any Linux distros for WSL, you must ensure that the "Windows Subsystem for Linux" optional feature is enabled:
  1. Open PowerShell as Administrator and run:
    PowerShell
    Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
    
  2. Restart your computer when prompted.

Step 2: continue Ubuntu installation.

Other ref:
Step3: in case you need python3 and numpy.

       Start by updating the package list using the following command:
  1. sudo apt update
  2. Use the following command to install pip for Python 3:
    sudo apt install python3-pip
    The command above will also install all the dependencies required for building Python modules.
  3. Once the installation is complete, verify the installation by checking the pip version:
    pip3 --version

Install Numpy Module using PIP

Using the appropriate PIP python version installed on your system execute the following pip3 command to install the python Numpy module:
$ pip3 install numpy
All done. Check for the Numpy's version:
$ python3 -c "import numpy; print(numpy.__version__)"
1.14.2

Tuesday, January 21, 2020

401k IRA


Uncle Sam 养老金从入门到精通——401(k), Backdoor Roth IRA



上次讲的收入税会对本文很有帮助,欢迎参考: vanshady:Uncle Sam 收入税从入门到精通

不知道大家有没有感觉每年给Uncle Sam交那么多税很酸爽,交了那么多税怎么可能财务自由嘛?
而养老金是一个非常好的避税途径,不仅可以降低当年税表上写的收入所得,而且甚至有时候养老金账户的收入所得也是免税的。而养老金的缺点也很显然,作为养老金账户,通常在59.5岁前(是的,真的有这个.5)把钱提出来需要交罚金和税。简单来说就是牺牲了钱的流动性,换来少交税以及59.5岁后有足够的饭钱。
好了,废话不多说,直接上干货,记得先点赞再收藏哦~
先说几个概念:
  • tax-free:这些钱以后不用交税,好处显而易见。
  • tax-deferred: 这些钱现在不交税,以后交税。好处在于这笔钱一开始可能落在了更高的tax bracket,而取出来就的时候,比如退休的时候取出来,因为你只会取你需要的部分,而你退休了也显然不会有工资了,所以通常在一个更低的tax-bracket。

话题转回退休账户,从退休账户的提供者来说有两种,401K和IRA。

401K

401K是公司提供的退休金账户。所以如果你跳槽了,就只有三个选择
  1. cash out并且支付penalty和tax,显然一个坏选择
  2. 保留,但是你的401K选择会更受限制
  3. 转成新公司的401K
  4. 转成自己的IRA

IRA

而IRA,Individual Retirement Account,就像名字一样,是你自己的退休账户,你有更多的自主权和投资选择。

简单来说401k是公司提供的退休账户,IRA是自己开的退休账户。401k的好处是会有一些特殊的fund(比如各种Vanguard institutional fund),平常的账户买不到,或者门槛非常高(百万级别的minimal investment requirement)。同时因为IRA是自己开户的,投资选择和类别也非常多(比如各种note),所以各有优缺点。

而退休账户类型主要有三种,Traditional,After-Tax和Roth。

Traditional

你直接把你的税前工资打进去,所以这个部分就不会算税了,i.e. contributions是deductible的。而Traditional的账户里你一开始打进去的钱和最后赚的钱,取出来的时候再收税,所有contributions+capital gains都是tax-deferred

After-Tax

顾名思义,这个账户让你把你after-tax的工资打进去。你会说我明明已经交了税,我还要把前放到退休金账户有什么好处呢?
类似于Traditional,你的capital gains是tax-deferred,但你的contributions是after-tax的。

Roth

Roth账户是以当年推动立法的主要支持者 Senator William Roth of Delaware命名的。
Roth的contribution可以说pre-tax的就像traditional一样,或者是after-tax的。大部分人都是After-tax的contribution,原因就在于Pre-tax的contribution和Traditional一起算在$19,000的cap里,而通常Traditional惠更划算一些。
Roth最大的好处便是投资所得是TAX-FREE的,所以如果你如果你妙手生花让这些钱翻10倍,Uncle Sam不会从里面拿走任何钱。


==
Notes:
https://www.nerdwallet.com/blog/investing/401k-rollover-ira-guide/

1.Traditional(=Pre-Tax): 你直接把你的税前工资打进去,所以这个部分就不会算税了,i.e. contributions是deductible的。而Traditional的账户里你一开始打进去的钱和最后赚的钱,取出来的时候再收税,所有contributions+capital gains都是tax-deferred

2.After-Tax: 顾名思义,这个账户让你把你after-tax的工资打进去。你会说我明明已经交了税,我还要把前放到退休金账户有什么好处呢? 类似于Traditional,你的capital gains是tax-deferred,但你的contributions是after-tax的。

3.Roth: Roth账户是以当年推动立法的主要支持者 Senator William Roth of Delaware命名的。
Roth的contribution可以说pre-tax的就像traditional一样,或者是after-tax的。大部分人都是After-tax的contribution,原因就在于Pre-tax的contribution和Traditional一起算在$19,000的cap里,而通常Traditional惠更划算一些。
Roth最大的好处便是投资所得是TAX-FREE的,所以如果你如果你妙手生花让这些钱翻10倍,Uncle Sam不会从里面拿走任何钱

https://www.nerdwallet.com/blog/investing/401k-rollover-ira-guide/
https://www.fidelity.com/learning-center/personal-finance/retirement/rolling-over-retirement-assets


FAQ:
https://www.fidelity.com/retirement-ira/rollover-faq

Can I roll over an old 401(k) that has both pre-tax and after-tax money in it?
You can, but it is important to select the right IRA for your needs. A Traditional (or Rollover) IRA is typically used for pre-tax assets because savings will stay invested on a tax-deferred basis and you won't owe any taxes on the rollover transaction itself. However, if you roll pre-tax assets into a Roth IRA, you will owe taxes on those funds. For after-tax assets, your options are a little more varied. You can roll the funds into a Roth IRA tax-free. You also have the option of taking the funds in cash or rolling them into an IRA along with your pre-tax savings. If you choose the latter option, it is important that you keep track of the after-tax amount so that when you start taking distributions, you'll know which funds have already been taxed. IRS Form 8606 is designed to help you do just this. Before making a decision, please consult with a tax advisor about your specific situation.

Wednesday, December 25, 2019

Qi Lu, A role model. 5 Hour sleep

You're an inspiration, have you ever heard of Qi Lu? He is a quiet legend in Silicon Valley that also grew up in a rural village in China. He spent years working at a dock, saving up money hoping one day to work in America. He believed the one thing God made sure everyone was equal in, was the time people have in a day. He experimented with his body and realized he only needed 5 hours of sleep per day to feel awake. He spent the day time working and at night researching and writing computer science papers (this went on for years). One day by pure luck, he was able to sit in on a lecture given by a Carnegie Mellon professor who was giving a lecture on a CS topic. Lu was participating and asking very complex questions which intrigued the professor. After the talk the professor asked if Lu had done any research work and if he could show him. WIth a big smile Lu said wait one moment and brought back (I think it was 5) his research papers. The professor gave him an offer to study in America, on a full ride paid by the professor himself. This man ended up becoming a Microsoft executive, COO of Baidu (Google of China) and is now the head of Y combinator. I read this story in the book the Third Door. One of his quotes paraphrased: "Luck is like a bus, it comes and go's, the only way your going to get on is to be prepared and have your ticket"



Ref:

https://leetcode.com/discuss/career/458113/my-inspirational-journey-to-study-in-the-us-and-then-summer-intern-at-google

Friday, December 20, 2019

[solution] how to mount external hard drive after reinstalling Ubuntu system

Note, your external hard drives are still there, you only need to mount them properly.
For example, in my case, I have two external hard drives, one has 4T space and antoher have 2T space. I want to name them as 4T and 2Tssd, respectively.
Here is how:

#step1: check the disk information, pay attention to the external drive:
sudo fdisk -l
#Your screen display lots of information, and you should find something like:
...
Disk /dev/sda: 3.7 TiB, 4000787030016 bytes, 7814037168 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disklabel type: gpt
Disk identifier: 6047D23B-339C-4AE5-90C5-C0DD7F75FE22

Device     Start        End    Sectors  Size Type
/dev/sda1   2048 7814035455 7814033408  3.7T Linux filesystem


Disk /dev/sdb: 1.9 TiB, 2048408248320 bytes, 4000797360 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x93a92f38

Device     Boot Start        End    Sectors  Size Id Type
/dev/sdb1        2048 4000797359 4000795312  1.9T 83 Linux

#step2, prepare mounting poing
sudo mkdir -p /media/2Tssd
sudo mkdir -p /media/4T

#step3: mount
sudo mount /dev/sdb1 /media/2Tssd
sudo mount /dev/sda1 /media/4T

Wednesday, November 20, 2019

[学Python/Perl] 一些刷题常用的 python 技巧

Ref: https://www.1point3acres.com/bbs/thread-543794-1-1.html

Python 越来越多地成为大家刷题的主流语言,主要原因是它的语法非常简洁明了。因此我们能节省更多的时间,来关注算法和数据结构本身。

而用好 Python 自身独有的一些语法特性,不仅能更节省时间,也能让代码看起来更加优雅。这里我总结了一些我自己刷题过程中用到的一些常用的功能。以下以 python3 为例, python2 略有差异。

List
Python 的列表 List 基本就是其它语言的 Array.

Initialization 初始化
List 的初始化一般用 List comprehension,往往能一行解决问题

[Python] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
# 1d array
l = [0 for _ in range(len(array)]
# or
l = [0] * len(array)
 
# 2d
l = [[0] for i in range(cols) for j in range(rows)]


# or
l = [0] * len(array)[/mw_shl_code]
l = [0 for _ in range(len(array)]
# or
l = [0] * len(array)[/mw_shl_code]


# 2d
l = [[0] for i in range(cols) for j in range(rows)]
Start from the behind
你可以轻松从后往前访问:

lastElement = l[-1]

lastTwo = l[-2:]

for i in range(0, -10, -1)
# 0, -1, -2, -3, -4, -5, -6, -7, -8, -9

copy 复制

shallow copy 浅拷贝

l2 = l1[:]
# or
l2 = l1.copy()
浅复制的问题在于,如果 l1 内部还有 list,那么这种嵌套的索引不能被复制,比如:

[Python] 纯文本查看 复制代码
?
01
02
03
04
05
a = [1, 2, [3, 4]]
b = a[:]
a[2].append(5)
print(b)
# [1, 2, [3, 4, 5]]


deep copy 深拷贝

所以如果要做深拷贝,要节制自带库 copy

import copy

copy.deepcopy()

enumerate 枚举

当我们需要枚举一个数组并同时获得值与 index 的时候可以使用:

l = ["a", "b", "c"]

for i, v in enumerate(l):
    print(i, v)
# 0 a
# 1 b
# 2 c

zip

zip 本意就是拉链,可以想象成将两个数组像拉链一样挨个聚合:

[Python] 纯文本查看 复制代码
?
01
02
03
04
05
>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> zipped = zip(x, y)
>>> list(zipped)
[(1, 4), (2, 5), (3, 6)]


reduce

reduce 可以分别对相邻元素使用同一种计算规则,同时每一步结果作为下一步的参数,很典型的函数式编程用法。
[Bash shell] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
# importing functools for reduce()
import functools
# initializing list
lis = [ 1, 3, 5, 6, 2, ]
 
# using reduce to compute sum of list
print ("The sum of the list elements is : ",end="")
print (functools.reduce(lambda a,b : a+b,lis))
 
# The sum of the list elements is : 17


map

可以将参数一一映射来计算, 比如

date = "2019-8-15"
Y, M, D = map(int, date.split('-'))
# Y = 2019, M = 8, D = 15

deque

list 删除末尾的操作是O(1)的,但是删除头操作就是O(n),这时候我们就需要一个双端队列 deque。首尾的常规操作为:

append,添加到末尾
appendleft, 添加到开头
pop, 剔除末尾
popleft,移除开头

sorted

list 自身有自带的 sort(), 但是它不返回新的 list. sorted 能返回一个新的 list, 并且支持传入参数reverse。

比如我们有一个 tuple 的数组,我们想按照 tuple 的第一个元素进行排序:

l1 = [(1,2), (0,1), (3,10) ]

l2 = sorted(l1, key=lambda x: x[0])

# l2 = [(0, 1), (1, 2), (3, 10)]
这里的 key 允许传入一个自定义参数,也可以用自带函数进行比较,比如在一个 string 数组里只想比较小写,可以传入key=str.lower

l1 = ["banana","APPLE", "Watermelon"]
l2 = sorted(l1, key=str.lower)
print(l2)

# ['APPLE', 'banana', 'Watermelon']
lambda
你注意到我们在上面使用了 lambda 来定义一个匿名函数,十分方便。如果你熟悉其它语言类似 JS 的话,可以把它理解成一个 callback 函数,参数名一一对应就行。

cmp_to_key

在 python3 中,sorted 函数取消了自带的cmp函数,需要借助functools 库中的 cmp_to_key来做比较。
比如如果要按照数组元素的绝对值来排序:

[Bash shell] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
from functools import cmp_to_key
def absSort(arr):
    newarr = sorted(arr, key = cmp_to_key(sortfunc))
    return newarr
def sortfunc(a, b):
    if abs(a) < abs(b):
      return -1
    elif abs(a) > abs(b):
      return 1
    else:
      return a - b


set

set 的查找操作复杂度为O(1),有时候可以替代dict 来存储中间过程。

add : set 的添加是 add 不是append
remove vs discard: 都是删除操作,区别在于remove不存在的元素会报错,discard不会。
union, intersection: 快速获得并集和交集,方便一些去重操作。

dict

字典,相当于其它语言中的map, hashtable, hashmap之类的,读取操作也是O(1) 复杂度

keys(), values(), items()
这三个方法可以分别获得key, value, {key: value}的数组。

setdefault

这个函数经常在初始化字典时候使用,如果某个key在字典中存在,返回它的value, 否则返回你给的 default 值。比如在建一个 trie 树的时候

[Python] 纯文本查看 复制代码
?
01
02
03
node = self.root
for char in word:
     node = node.setdefault(char, {})


OrderedDict

OrderedDict 能记录你 key 和 value 插入的顺序,底层其实是一个双向链表加哈希表的实现。我们甚至可以使用move_to_end这样的函数:

>>> d = OrderedDict.fromkeys('abcde')
>>> d.move_to_end('b')
>>> ''.join(d.keys())
'acdeb'
# 放开头
>>> d.move_to_end('b', last=False)
>>> ''.join(d.keys())
'bacde'

defaultdict

defaultdict可以很好地来解决一些初始化的问题,比如 value 是一个 list,每次需要判断 key 是否存在的情况。这时我们可以直接定义

d = defaultdict(list)

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
for k, v in s:
     d[k].append(v)
sorted(d.items())
# [('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

heapq

heapq 就是 python 的 priority queue,heapq[0]即为堆顶元素。

heapq 的实现是小顶堆,如果需要一个大顶堆,常规的一个做法是把值取负存入,取出时再反转。
以下是借助 heapq 来实现 heapsort 的例子:

>>> def heapsort(iterable):
...     h = []
...     for value in iterable:
...         heappush(h, value)
...     return [heappop(h) for i in range(len(h))]
...
>>> heapsort([1, 3, 5, 7, 9, 2, 4, 6, 8, 0])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

bisect

python 自带二分查找的库,在一些不要求实现 binary search,但是借助它能加速的场景下可以直接使用。

bisect.bisect(a, x, lo=0, hi=len(a))
这里的参数分别为 数组,要查找的数,范围起始点,范围结束点
相似函数还有

bisect.bisect_left
bisect.bisect_right
分别返回可以插入 x 的最左和最右 index

Counter

Counter 接受的参数可以是一个 string, 或者一个 list, mapping

>>> c = Counter()                           # a new, empty counter
>>> c = Counter('gallahad')                 # a new counter from an iterable
>>> c = Counter({'red': 4, 'blue': 2})      # a new counter from a mapping
>>> c = Counter(cats=4, dogs=8)             # a new counter from keyword args
most_common(n)
可以得到出现次数最多的 n 个数:
>>> Counter('abracadabra').most_common(3)  # doctest: +SKIP
[('a', 5), ('r', 2), ('b', 2)]

strings

ord, char

ord 返回单个字符的 unicode:

>>> ord('a')
97
char 则是反向操作:

>>> chr(100)
'd'

strip

移除 string 前后的字符串,默认来移除空格,但是也可以给一个字符串,然后会移除含有这个字符串的部分:

>>> '   spacious   '.strip()
'spacious'
>>> 'www.example.com'.strip('cmowz.')
'example'

split

按照某个字符串来切分,返回一个 list, 可以传入一个参数maxsplit来限定分离数。

>>> '1,2,3'.split(',')
['1', '2', '3']
>>> '1,2,3'.split(',', maxsplit=1)
['1', '2,3']
>>> '1,2,,3,'.split(',')
['1', '2', '', '3', '']

int/ float

最大, 最小 number
有时候初始化我们需要设定 Math.max() 和 Math.min(), 在 python 中分别以 float('inf') 和 float('-inf')表示

我们也可以这么做:

[Python] 纯文本查看 复制代码
?
01
02
03
04
import sys
 
#maxint
Max = sys.maxint


除法

在 python3 中, / 会保留浮点,相当于 float 相除,如果需要做到像 pyhton2 中的 int 相除,需要 //:

>>> 3 / 2
1.5
>>> 3 // 2
1
次方
在 python 中为 **:

>>> 2 ** 10
1024

conditions

在 python 的三项表达式(ternary operation) 与其它语言不太一样:

res = a if condition else b
它表示如果 condition 满足,那么 res = a, 不然 res = b,在类 c 的语言里即为:

res = condition ? a : b;

any, all

any(), all()很好理解,就是字面意思,即参数中任何一个为 true 或者全部为 true 则返回 true。经常可以秀一些骚操作:
比如 36. Valid Sudoku 这题:

[Python] 纯文本查看 复制代码
?
01
02
03
04
05
06
class Solution:
    def isValidSudoku(self, board: List[List[str]]) -> bool:
        row = [[x for x in y if x != '.'] for y in board]
        col = [[x for x in y if x != '.'] for y in zip(*board)]
        pal = [[board[i+m][j+n] for m in range(3) for n in range(3) if board[i+m][j+n] != '.'] for i in (0, 3, 6) for j in (0, 3, 6)]
        return all(len(set(x)) == len(x) for x in (*row, *col, *pal))


itertools
这是 python 自带的迭代器库,有很多实用的、与遍历、迭代相关的函数。

permutations 排列

permutations('ABCD', 2)
# AB AC AD BA BC BD CA CB CD DA DB DC

combinations 组合

combinations('ABCD', 2)
# AB AC AD BC BD CD

groupby 合并

https://leetcode.com/problems/swap-for-longest-repeated-character-substring/discuss/355852/Python-Groupby/322898

[k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
[list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D

functools

这个库里有很多高阶函数,包括前面介绍到的cmp_to_key 以及 reduce,但是比较逆天的有 lru_cache,即 least recently used cache. 这个 LRU Cache是一个常见的面试题,通常用 hashmap 和双向链表来实现,python 居然直接内置了。

用法即直接作为 decorator 装饰在要 cache 的函数上,以变量值为 key 存储,当反复调用时直接返回计算过的值,例子如下:

lru_cache
https://leetcode.com/problems/stone-game-ii/discuss/345230/Python-DP-Solution

[Python] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
def stoneGameII(self, A: List[int]) -> int:
    N = len(A)
      for i in range(N - 2, -1, -1):
    A += A[i + 1]
      from functools import lru_cache
    @lru_cache(None)
    def dp(i, m):
        if i + 2 * m >= N: return A
        return A - min(dp(i + x, max(m, x)) for x in range(1, 2 * m + 1))
    return dp(0, 1)


resource


这是一个大神用各种 Python trick 解题的 repo,可供娱乐:

https://github.com/cy69855522/Shortest-LeetCode-Python-Solutions

当然 Leetcode 讨论区还会经常见到 StefanPochmann 或者 lee215这样的大神 Po 一些很秀技的 python 代码,都是学习范本