面试官让候选人写一个函数,把嵌套字典拍平。要求输出{&39;a.b.c&39;: 1}这种格式。五分钟内写完的人不到三个。剩下的人全卡在递归上。
有个候选人写了三层for循环嵌套,他自己都不好意思提交。还有个候选人用了json.dumps再拆分字符串,跑通了一个用例,换一个带数组的字典立刻崩溃。
这道题不考算法,考的是对Python基础数据结构的理解。递归不难,难的是想不想得到递归。很多人一上来就想着用循环硬拆,拆到一半发现层数不定,直接懵了。
第一个坑是可变默认参数。很多人写递归函数喜欢默认一个空字典收集结果。第一次调用没问题,第二次调用就会带着上次的数据。这个知识点书上都写过,面试时候全忘了。
第二个坑是键名拼接。有人用列表存路径,每次递归传一个新列表,代码又长又绕。其实直接传字符串拼接就行,回溯的时候字符串天然不可变,不用考虑还原问题。
第三个坑是处理非字典值。很多人只判断了isinstance(value, dict),忘了collections.abc.Mapping。结果碰到OrderedDict或者自定义映射类就出错。面试官当场给个defaultdict,直接挂掉。
正确答案应该短到十行以内。递归出口先判断类型,不是字典就写入结果。是字典就遍历每个键值对,把父路径加前缀传下去,不用额外数据结构。
考完这道题,我问一个候选人为什么卡住。他说平时用pandas处理数据,字典都是规整的二维结构,从没想过拍平这回事。这就是差距,工具用多了,基础反而不牢。
另一个候选人写了递归但没处理空字符串键名。输入{&39;&39;: {&39;a&39;: 1}},输出变成{&39;.a&39;: 1}。他说业务里不会有空键名。业务里不会有,那考试里就可以有?
这道题最实用的解法是用栈做迭代。递归虽然短,但深度超过一千层会爆栈。用栈把需要处理的字典存起来,每次弹出一个处理,结果放列表里,最后转成字典。代码稍长,但稳。
很多人觉得这种题是八股文,实际工作用不上。真的用不上吗?配置中心的数据就是多层嵌套的YAML转字典,要批量修改就必须拍平。接口返回的复杂JSON结构,做字段映射也要拍平。
我见过最离谱的答案,用eval加replace处理字符串,先把字典转成repr,再正则替换括号。跑通了一个简单用例,面试官问复杂嵌套怎么处理,他自己都说不清楚。
最后说个有趣的现象。会写这个函数的人,基本都能正确解释深浅拷贝的区别。不会写的人,连生成器怎么工作都讲不明白。基础扎实的人,各知识点是连通的,不扎实的人,每个知识点都是孤岛。
这道题不是一个技术门槛,是面镜子。照出你平时的编码习惯,照出你读源码的深度,照出你遇到没见过的数据时第一反应是查资料还是动手试。面试不是考倒你,是让你看清自己。
如果你现在能闭眼写出这个函数,恭喜你,基础及格了。写不出来的,别急着刷题,把官方文档的dict和collections章节重新读两遍,比什么都有用。