Python技术迷

公司宣布全员大小周,不同意可以离职。我问面试的人可以接受吗,结果她说:只要工资在8000以上,不要说大小周了,996都可以接受!

公司直接宣布全员大小周,还甩一句:不同意可以离职。这个味儿太熟了,像那种“通知你一下,不是跟你商量”的职场老配方。

更离谱的是,楼主去面试别人,顺口问能不能接受大小周。结果对方来一句,只要工资8000以上,别说大小周了,996都能接受。

Image

不是人家多爱加班,也不是她天生能扛。很多时候就是没得选。房租要交,饭要吃,简历投出去半天没回音,真有人愿意给8000,很多人嘴上再硬,心里也得盘算一下。

老板听了估计开心坏了:你看,不是我们压榨,是有人愿意。

但打工人看完真的笑不出来。一个人愿意忍,不代表这事就合理。只是现在大家被生活按着头,连拒绝都变得很贵。

算法题:统计实验的数量

这题别一上来就 Counter,会少数据

这题看着是统计,其实坑在“没出现的也要统计”。

实验表里只有已经发生过的记录,比如 IOS 做过 Programming,Web 做过 Reading。你要是顺手写一个 Counter,把出现过的组合数一遍,代码确实能跑,但结果少一截。

少哪一截?

少的是这种:

Android + Sports = 0
IOS + Reading = 0
Web + Sports = 0

这地方我一般不太信“遍历已有数据”这一套。因为已有数据只能告诉你发生过什么,不能告诉你哪些组合应该出现但没发生。

题目要的是完整报表,不是流水统计。

输入大概长这样:

experiments = [
    {"id": 4, "platform": "IOS", "name": "Programming"},
    {"id": 13, "platform": "IOS", "name": "Sports"},
    {"id": 14, "platform": "Android", "name": "Reading"},
    {"id": 8, "platform": "Web", "name": "Reading"},
    {"id": 12, "platform": "Web", "name": "Reading"},
    {"id": 18, "platform": "Web", "name": "Programming"},
]

平台是固定的:

platforms = ["Android", "IOS", "Web"]

实验类型也是固定的:

names = ["Reading", "Sports", "Programming"]

这两个固定列表很关键。它俩才是最后结果的骨架。

我会先把真实数据扫一遍,只统计发生过的组合:

defcount_experiments(experiments):
    platforms = ["Android", "IOS", "Web"]
    names = ["Reading", "Sports", "Programming"]

    hit = {}

for row in experiments:
        key = (row["platform"], row["name"])
        hit[key] = hit.get(key, 0) + 1

    ans = []
for platform in platforms:
for name in names:
            ans.append({
"platform": platform,
"experiment_name": name,
"num_experiments": hit.get((platform, name), 0)
            })

return ans

这里有个小细节,最后生成结果时,不是遍历 hit,而是遍历 platforms * names。

这一步就是把 0 补回来。

跑一下:

result = count_experiments(experiments)

for item in result:
    print(item)

输出会是这样:

{'platform': 'Android', 'experiment_name': 'Reading', 'num_experiments': 1}
{'platform': 'Android', 'experiment_name': 'Sports', 'num_experiments': 0}
{'platform': 'Android', 'experiment_name': 'Programming', 'num_experiments': 0}
{'platform': 'IOS', 'experiment_name': 'Reading', 'num_experiments': 0}
{'platform': 'IOS', 'experiment_name': 'Sports', 'num_experiments': 1}
{'platform': 'IOS', 'experiment_name': 'Programming', 'num_experiments': 1}
{'platform': 'Web', 'experiment_name': 'Reading', 'num_experiments': 2}
{'platform': 'Web', 'experiment_name': 'Sports', 'num_experiments': 0}
{'platform': 'Web', 'experiment_name': 'Programming', 'num_experiments': 1}

如果用 Counter,代码还能再短一点:

from collections import Counter

defcount_experiments_v2(experiments):
    platforms = ["Android", "IOS", "Web"]
    names = ["Reading", "Sports", "Programming"]

    counter = Counter(
        (row["platform"], row["name"])
for row in experiments
    )

return [
        {
"platform": platform,
"experiment_name": name,
"num_experiments": counter[(platform, name)]
        }
for platform in platforms
for name in names
    ]

但别被这几行骗了。真正要想清楚的是:统计表的维度从哪里来。

这题不是难在计数,计数就是哈希表。难的是结果集不是由数据决定的,而是由固定枚举决定的。

复杂度也没什么花活。假设实验记录有 n 条,扫一遍是 O(n)。后面平台 3 个、实验 3 个,最多补 9 条,算常数。

以后看到这种题,先别急着写聚合。先问一句:结果里要不要包含 0?

要包含 0,就先搭骨架,再往上填数。这个顺序别反。