0%

如何对Python中的字典进行排序

今天想到了去年在面一家startup的时候碰到的一个面试题。给定一组json字符串构成的API回调数据,按照某个特定的排列顺序进行输出。类似于下面这个栗子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
API_response = {
"summary": {
"info1": 4200,
"info2": 30
},
"trips": [
{
"trip_id": 10001,
"duration": 1956,
"distance": 16
},
{
"trip_id": 10002,
"duration": 891,
"distance": 4
},
{
"trip_id": 10003,
"duration": 898,
"distance": 10
},
{
"trip_id": 10004,
"duration": 898,
"distance": 5
},
]
}

我们可以很容易地想到在SQL环境下的操作方法,即直接order by。但在Python的环境下,如果我们需要按照duration从小到大的顺序排列,且在满足相同duration的时候,按照distance从大到小输出对应的数据,应该如何操作呢?

第一步是需要将json字符串转为Python的字典(dict)类型,json和Python的字典类型看起来非常类似,但是它们还是有一些区别的。比如

  1. json是字符串str类型,而字典是Python常见六大类型之一,和str平起平坐。
  2. json的话强制需要用双引号来表示key的值(字符串和数字都需要,不能用单引号。字典的话数字作为key不用加双引号,且字符串的表示用单引号和双引号都可以。
  3. json空值是null, 字典空值为None(这个延续了Python的光荣传统)
  4. json的key可以重复,字典不行,每个key是唯一的。

字典和json的转换可以通过json包中的json.load()和json.dumps()进行实现(需要先导入json包),json转字典使用的是json.load()操作(参数为json,返回为字典),而字典转json使用的是json.dumps()操作(参数为字典,返回为json)

需要注意的是json包中还有另外一个函数dump(),这个也是将python中的数据类型转为json格式的函数,但是json.dump()和我们用的json.dumps()是有区别的。

  1. json.dump()的作用是把数据转换为json格式并存储在文件中,因此它有两个参数,第一个参数是需要被转换为json格式的变量,第二个参数是文件对象。
  2. json.dumps()的作用是把数据转换为json字符串,并没有存储到文件中的操作,所以只有一个参数(需要转换为json格式的变量)并返回一个str字符串

第二步就是要对字典进行排序了,字典的排序和list类似,同样也有sort和sorted方法,sort修改本身,sorted不修改本身,返回新值。
回到这个栗子,我们可以写出这样的代码。

1
API_response["trips"].sort(key = lambda x:(x["duration"], -x["distance"]))

这种方式是直接修改字典本身的,当然也可以通过sorted方法来返回该部分字典的排序结果。(如果需要按照duration从大到小,相同duration情况下从小到大的话,在sort/sorted函数的参数中,添加reverse = True即可)

1
2
3
API_response2 =  dict()
API_response2["summary"] = copy.deepcopy(API_response["summary"])
API_response2["trips"] = sorted(API_response["trips"], key = lambda x:(x["duration"], -x["distance"]))

经过排序过后可以看到最后得到的输出如下(原输出为一行数据,不易阅读,因此做了一些格式上的调整)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
API_response = {
"summary": {
"info1": 4200,
"info2": 30
},
"trips": [

{
"trip_id": 10002,
"duration": 891,
"distance": 4
},
{
"trip_id": 10003,
"duration": 898,
"distance": 10
},
{
"trip_id": 10004,
"duration": 898,
"distance": 5
},
{
"trip_id": 10001,
"duration": 1956,
"distance": 16
}
]
}

可以看出经过排序之后得到了我们想要的输出(先按duration从小到大,在duration相同的情况下按distance从大到小)
之后如果想要再换回json格式的话,只要使用json.dumps()函数就可以了。