专栏首页面向人生编程一道快速考察 Python 基础的面试题

一道快速考察 Python 基础的面试题

这是前一阵子群友发在群里的一道面试题,利用 Python 字典的特性,可以巧妙地使用精简代码达成完美解。

题目

将 data 转换成 new_data 这种形式,写出转换过程。

data = {
    'a_b_h':1,
    'a_b_i':2,
    'a_c_j':3,
    'a_d':4,
    'a_c_k':5,
    'a_e':6
}

new_data = {
    'a':{
        'b':{
            'h':1,
            'i':2
        },
        'c':{
            'j':3,
            'k':5
        },
        'd':4,
        'e':6
    }
}

可以看出,转换的过程是将 key 的下划线进行拆分,然后下划线后边的字符嵌套在前面字符的值中。

感兴趣就打开 IDE,自己先试着解一下。

解题思路

你应该很快想到,主要思路是将下划线 split 后,然后依次使用字符生成内层字典,当达到最后一个字符时将数字作为值。

那么关键点在于,如何不断地获得内层字典去修改呢?实际本题就是考察你是否理解 Python 字典是引用传递这个特性。

什么是引用传递?我们知道 Python 中字典和列表对象都是可变对象,同一个字典对象的变量不管如何传递,只要改变其中一个变量会同步修改其他变量。这是因为变量存储的只是可变对象的引用,无论调用哪个变量,返回的依然是同一个对象。比如:

new_data = {}
tmp = {}
new_data['a'] = tmp
print(new_data)  # {'a': {}}
tmp['b'] = 1
print(new_data)  # {'a': {'b': 1}}

如上,利用这个特性,将内层字典赋值给一个中间变量,然后改变这个中间变量,即可同步修改最终的 new_data 变量。

根据这个思路,初步代码如下:

data = {
    'a_b_h':1,
    'a_b_i':2,
    'a_c_j':3,
    'a_d':4,
    'a_c_k':5,
    'a_e':6
}

new_data = {}

for key, value in data.items():
    keys = key.split('_')
    tmp = new_data
    last = len(keys) - 1  # 最后一个 key 的索引值 
    for i, k in enumerate(keys):
        if i == last:
            tmp[k] = value
            continue
        if k not in tmp:
            sub_tmp = {}
            tmp[k] = sub_tmp
            tmp = sub_tmp
        else:
            tmp = tmp[k]

这也是群友给出的第一版答案,这样写并没有多大问题,但是代码比较繁琐,肯定还有优化空间。

我们可以只使用一个中间变量即可,进一步优化:

for field, value in data.items(): 
    keys = field.split('_') 
    tmp = new_data 
    last = len(keys) - 1
    for i, k in enumerate(keys): 
        if k not in tmp:
            tmp[k] = {} if i < last else value
        tmp = tmp[k]  # 将内层 dict 传给 tmp

上面这个代码看似很简洁了,但是仍然还有两个 if 判断,如果不是使用了三元表达式的话,还会更多行。

所以可以进一步优化:

for field, value in data.items(): 
    keys = field.split('_') 
    tmp = new_data 
    for k in keys[:-1]: 
        tmp = tmp.setdefault(k, {})
    tmp[keys[-1]] = value

我们省略掉了 last 来判断最后一个字符的索引,直接通过 keys[:-1] 避开最后一个字符,末尾再单独生成数字键值对。

这里还使用字典的一个内置方法 —— setdefault

dict.setdefault(key, default=None) 方法和 get 方法类似,只是如果键不存在于字典中,不仅会返回 default 参数的值,还同时会用该值自动生成一个键值对。

if k not in tmp:
    tmp[k] = {}
v = tmp[k]

# 等价于

v = tmp.setdefault(k, {})

最终我们使用了 6 行代码就解出该题,这也是接近最简代码。

如果使用字典引用的特性是合格分的话,那么当你用出 setdefault 这个方法后,面试官已经给你打了优秀,因此一定要熟悉基础数据对象的所有内置方法

本文分享自微信公众号 - 面向人生编程(LifeOriented),作者:张凯强

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-02-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 一道快速考察 Python 基础的面试题

    可以看出,转换的过程是将 key 的下划线进行拆分,然后下划线后边的字符嵌套在前面字符的值中。

    数据森麟
  • Go的面试笔试基础考察区别点

    #############################分割线###############################################

    小诚信驿站
  • 编程 | Python基础面试题快速自测, 你真的懂Python基础么?

    Python基础面试题快速自测, 你真的懂Python基础么?先来几道题试试,比如: 1. What will be the output of the co...

    小莹莹
  • 一道面试题的思考

    在继承中new和override相同点和区别?看下面的代码,有一个基类A,B1和B2都继承自A,并且使用不同的方式改变了父类方法Print()的行为。测试代码...

    圣杰
  • 一个简单但能考察C语言基础的题目,试试?

    各位,今天有人在后台问了一道C语言题目,题目本身比较简单,但是挺有意思的就拿出来跟大家分享一下,请看题:

    7089bAt@PowerLi
  • Kafka的10道基础面试题

    许久不见,各位读者,上次更文已经是去年了,快两个月没发文章了,谢谢大家没有取关。没有加我微信的朋友,可能不知道我于去年12月当上了爸爸,算是我人生的一个重大变化...

    草捏子
  • 一道面试题引起的思考

    今天在认真干(划)活(水)的时候,看到群里有人发了一道头条的面试题,就顺便看了一下,发现挺有意思的,就决定分享给大家,并且给出我的解决方案和思考过程。

    嘿嘿嘿
  • 一道面试题引发的思考

    为什么呢?那么我们怎么来发现它背后的秘密呢?答案只有一个:那就是通过源码来解惑(ArrayList部分源码)。

    阿豪聊干货
  • 快速掌握JavaScript面试基础知识(一)

    根据StackOverflow 调查, 自 2014 年一来,JavaScript 是最流行的编程语言。当然,这也在情理之中,毕竟 1/3 的开发工作都需要一些...

    Fundebug

扫码关注云+社区

领取腾讯云代金券