Python技术迷

某大厂员工爆料:提了离职后公司电脑的灯一直亮着,细思极恐,都要走了,还要被时刻监控!

刚看到个贴子,说有大厂员工提了离职后,公司电脑指示灯一直亮着,明明关了摄像头还闪,搞得像被24小时监控一样,怪瘆人的。

Image

很多公司确实装了各种安全管控软件,离职流程一跑,权限回收、数据备份、系统审计一堆动作,灯常亮也不一定真在监控你——但员工的恐惧感是真实的。

问题的根本还是在“透明度”。公司不提前说明、不解释清楚,让员工靠猜的,那自然容易引发误会。职场里最怕的不是制度严,而是莫名其妙的神秘操作。

不过话说回来,哪怕要管控,也得让人明白在管啥、为什么管。尊重感这东西,看不见,但扎心。【备注:文末可领最新资料】

面试题:查询员工的累计薪水

昨天晚上十一点多我还在公司楼下拿着奶茶刷工单,有个同事在群里问了句:“哥们儿,有没有现成的代码算员工累计薪水的?我这边报表要按月份累加那种。”我当时脑子一转,这不就是个前缀和问题嘛,用 Python 写两行就搞定的事,但一说就变成一长串,索性给你们完整唠一遍。

场景大概是这样的: 你有一堆发薪记录,每条记录里有三个关键字段:员工 ID、月份、当月发了多少钱。可能长这样:

emp_id  month   salary
1       202401  10000
1       202402  12000
1       202403  11000
2       202401  8000
2       202403  9000

领导要看的不是“每个月多少钱”,而是“看到这一个月为止,这个员工一共领了多少”。比如员工 1:

  • 202401 累计 = 10000
  • 202402 累计 = 10000 + 12000 = 22000
  • 202403 累计 = 22000 + 11000 = 33000

员工 2 还会出现“中间没发工资记录”的情况(比如 202402 没记录),那就只对存在的月份做累计就好了,不用硬凑出所有月份。

用自然点的话说,就是: 按员工分组,再按月份排序,然后一路往前加,边加边记下来。

思路其实就两步

我当时在工位上随手在本子上画了个小图,思路就两句:

  1. 先按 emp_id 把记录分堆,每一堆再按 month 从小到大排个序。
  2. 遍历这一堆记录,维护一个 running_sum,遇到一条工资就加上去,然后把“当前累计值”写回结果里。

复杂度也很直接: 总共有 n 条记录,排序大概是 O(n log n),遍历累加是 O(n),完全够大部分业务用,除非你们一个月几亿条发薪记录,那时候你再考虑更花活的东西。

用 Python 写一版最实在的

我懒得上什么花里胡哨的库,直接用 list + dict 搞完,代码差不多是这样:

from collections import defaultdict
from typing import List, Dict, Any

defcalc_cumulative_salary(records: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""
    records 里每条数据格式类似:
    {
        "emp_id": 1,
        "month": 202401,  # 或者 "2024-01" 都行,关键是能比较大小
        "salary": 10000,
    }
    返回结构会多一个字段 cumulative_salary
    """

# 1. 按员工分组
    grouped = defaultdict(list)
for r in records:
        grouped[r["emp_id"]].append(r)

    result = []

for emp_id, emp_records in grouped.items():
# 2. 按月份排序(注意 key 写对)
        emp_records.sort(key=lambda x: x["month"])

# 3. 按顺序做前缀和
        cum = 0
for r in emp_records:
            cum += r["salary"]
# 复制一份,别修改原数据的话就用 copy
            new_r = dict(r)
            new_r["cumulative_salary"] = cum
            result.append(new_r)

# 如果你希望整体也按 emp_id + month 排好再返回,可以再排一次
    result.sort(key=lambda x: (x["emp_id"], x["month"]))
return result


if __name__ == "__main__":
    data = [
        {"emp_id": 1, "month": 202401, "salary": 10000},
        {"emp_id": 1, "month": 202403, "salary": 11000},
        {"emp_id": 1, "month": 202402, "salary": 12000},
        {"emp_id": 2, "month": 202401, "salary": 8000},
        {"emp_id": 2, "month": 202403, "salary": 9000},
    ]

    res = calc_cumulative_salary(data)
for row in res:
        print(row)

这个跑出来大概是:

{'emp_id': 1, 'month': 202401, 'salary': 10000, 'cumulative_salary': 10000}
{'emp_id': 1, 'month': 202402, 'salary': 12000, 'cumulative_salary': 22000}
{'emp_id': 1, 'month': 202403, 'salary': 11000, 'cumulative_salary': 33000}
{'emp_id': 2, 'month': 202401, 'salary': 8000, 'cumulative_salary': 8000}
{'emp_id': 2, 'month': 202403, 'salary': 9000, 'cumulative_salary': 17000}

看着就挺像一个简单报表的底层数据对吧。

我晚上帮同事看代码的时候,他的几个小坑,顺便给你提一下:

一个是月份的字段,有人喜欢用字符串 "2024-01",有人用整数 202401。不管用哪个,只要排序规则是正确的就行,字符串就直接按字符串排;如果是日期对象比如 datetime.date,也可以,比较运算一样能用。

还有一个是“同一个员工同一个月多条记录”的情况,比如补发工资、绩效后来补算,这种你要提前想好业务规则: 是先合并成一个月一个总金额,再去做累计,还是保留多条记录,每条都算一个“更新后的累计值”。这一块不写清楚,后面业务吵起来你就会被拉进去背锅。

如果你用的是数据库算(比如 SQL 里的窗口函数 sum over partition by 之类),逻辑本质上跟我们这个 Python 前缀和是一样的,只不过把“分组 + 排序 + 累加”交给数据库做而已。

再加一个小变体

有时候领导会说:“我只看今年的累计就行,去年不用算进来。”那你就先把 records 过滤一下:

this_year_records = [r for r in records if str(r["month"]).startswith("2024")]
res = calc_cumulative_salary(this_year_records)

或者再极端一点:按部门 + 员工两层维度累计,那就把 key 换成 (dept_id, emp_id),其他逻辑不变。

行,我先去续个咖啡,你要是还想加个“按天累计”“滑动窗口累计”之类的,我们可以再接着改这个代码。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

🔥虎哥私藏精品🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB