跳转至

字典排序


基础版

按照字典的key或value排序

# 字典如下:
mydict1 = {'b': 3, 'd': 1, 'c': 2, 'a': 4}
mydict2 = {'name': '张三', 'age': '18岁', 'city': '深圳', 'tel': '13626266627'}
print('字典mydict1排序前:', mydict1)
print('字典mydict2排序前:', mydict2)
print()

print('按照字典的key排序:')
print()


def func1(mydict):
    """
    方法一:
    思路是将k和v以元组的形式组成列表并排序(会以元组的第一个元素的大小排序,即k),再遍历列表取出元组,
    元组中的元素分别是k和v,放到一个新的字典里,最后返回这个新字典
    """
    mydict2list = sorted([item for item in mydict.items()])  # 目的是将字典变成列表再用sorted()排序
    new_dict = {}  #
    for i in mydict2list:  # 遍历出来的i是一个元祖,包含key和value两个元素
        new_dict[i[0]] = i[1]
    print('方法一排序后:', new_dict)


func1(mydict1)
func1(mydict2)
print()


def func2(mydict):
    """
    方法二:
    用的还是方法一的思路,但是sorted()函数的返回值就是一个列表,所以不需要写列表推导式
    即sorted([item for item in mydict.items()])可以简写成sorted(mydict.items())
    """
    mydict2list = sorted(mydict.items())
    new_dict = {}
    for i in mydict2list:
        new_dict[i[0]] = i[1]
    print('方法二排序后:', new_dict)


func2(mydict1)
func2(mydict2)
print()


def func3(mydict):
    """
    方法三:
    mydict2list是一个列表,列表内的元素是一个个的元组,元组里包含两个元素
    分别是原始字典中的key和value,而dict()这个方法可以转化这种结构成字典
    所以将for循环省略,写成下面的方法
    """
    mydict2list = sorted(mydict.items())
    new_dict = dict(mydict2list)
    print('方法三排序后:', new_dict)


func3(mydict1)
func3(mydict2)
print()


def func4(mydict):
    """
    方法四:
    方法三中的两行代码可以合并成一行
    """
    print('方法四排序后:', dict(sorted(mydict.items())))


func4(mydict1)
func4(mydict2)
print()

print("""
总结下来,字典按照key排序的格式是:
dict(sorted(mydict.items()))
即,最外层是dict(),中间层是sorted(),最内层是被排序字典.items()
最终结果就是:dict(sorted(mydict.items())))
""")
print()

print('拓展:只要列表或者元祖中的元素,是成对儿出现的,都可以使用dict()将其转化成字典,例如:')
mylist = [['a', 1], ['b', 2], ('c', [4])]
print('列表:', mylist)
print('列表转字典:', dict(mylist))
mytuple = (['a', 1], [('b',), 2], ('c', [4]))
print('元组:', mytuple)
print('元组转字典:', dict(mytuple))
print()


def func5(mydict):
    """
    方法五:
    其中sorted()方法有个参数是key,可以指定参与比较的元素
    可以使用lambda函数来返回参与比较的元素,上述代码可以写成这样:
    """
    print('方法五排序后:', dict(sorted(mydict.items(), key=lambda x: x[0])))  # 对比方法四,发现key这个参数加不加都可以,加上的目的是为了引出后面的按照value排序


func5(mydict1)
func5(mydict2)
print()

print("""从方法一到方法四
总结出字典排序的核心语句是:sorted(mydict.items())
而方法五的核心语句是:sorted(mydict.items(),key=lambda x:x[0])
在sorted()方法中添加了一个参数key,表示排序条件是lambda x:x[0]
解释:
匿名函数 lambda x:y 中x表示传入的参数,y表示lambda 函数的返回值
所以 lambda x:x[0] 表示传入参数x返回参数x的第一个元素,即x[0]
而字典的items()方法将字典的k和v转化为了元组,并且被当作参数传给了lambda的x
x的结构是(k,v),x[0]就是k,也就是用字典的key作为排序条件
为了更加方便的理解匿名函数lambda,可以改写成正常的函数, 并输出x、x[0]的结果和类型
""")


def mykey(x):
    print('x及x的类型到底什么:', x, type(x))
    print('x[0]及x[0]的类型到底什么:', x[0], type(x[0]))
    return x[0]


print('方法五排序后:', dict(sorted(mydict1.items(), key=mykey)))
print('')
print('方法五排序后:', dict(sorted(mydict2.items(), key=mykey)))
print('')
print('从上面的输出结果可以看出x[0]就是字典的key值')

# 如此一来按照value排序只要把x[0]改成x[1]即可:
print('按照字典的value排序:')
print('排序后:', dict(sorted(mydict1.items(), key=lambda x: x[1])))
print('排序后:', dict(sorted(mydict2.items(), key=lambda x: x[1])))
print("""
按照value排序后发现“张三”在“深圳”前面
原因是python以较汉字的utf-8的编码值排序的
使用ord()方法可以得到汉族的Unicode编码(10进制)
ord('张')得出24352,ord('深')得出28145
所以‘张’排在‘深’前面
或者使用 '张'.encode() 得出E5BCA0,'深'.encode() 得出E6B7B1,比较16进制也能看出大小
""")

# 那么对于嵌套的字典结构如何排序呢?
dit = {
    'd': {'sort': 7},
    'a': {'sort': 3},
    'c': {'sort': 4},
    'b': {'sort': 1},
}
print('字典嵌套字典,按照被嵌套字典的key排序,即abcd排序:')
print('原始顺序:', dit)
print('按照key排序:', dict(sorted(dit.items(), key=lambda x: x[0])))
print('字典嵌套字典,按照被嵌套字典的value排序,即1347排序:')
print('按照key排序:', dict(sorted(dit.items(), key=lambda x: x[1]['sort'])))
print('')
print("为了方便理解,再次把lambda改写成正常的函数,并输出x[1]['sort']的值:")


def value(x):
    print(x, x[1], x[1]['sort'])
    return x[1]['sort']


print('按照value排序:', dict(sorted(dit.items(), key=value)))
print()

# 还是嵌套字典,但是嵌套字典的key不一样呢?
dit = {
    'd': {'sortd': 7},
    'a': {'sorta': 3},
    'c': {'sortc': 4},
    'b': {'sortb': 1},
}


def value(x):
    """
    这种情况下,就不能使用x[1]['sort'],因为被嵌套的字典的key不是统一的'sort',所以要通过字典的values()取出所有的key,
    但是values()的类型是dict_values,不能通过索引取出value,所以要转成列表
    即list(x[1].values()),此时的列表就一个元素,通过索引就能取出来
    最终的形式就是list(x[1].values())[0]
    """
    print(x[1], x[1].values(), list(x[1].values())[0])
    return list(x[1].values())[0]


print('按照value排序:', dict(sorted(dit.items(), key=value)))
print()

# 既然核心代码是list(x[1].values())[0],那么最终的写法就是:
print('按照value排序:', dict(sorted(dit.items(), key=lambda x: list(x[1].values())[0])))

输出:

字典mydict1排序前: {'b': 3, 'd': 1, 'c': 2, 'a': 4}
字典mydict2排序前: {'name': '张三', 'age': '18岁', 'city': '深圳', 'tel': '13626266627'}

按照字典的key排序:

方法一排序后: {'a': 4, 'b': 3, 'c': 2, 'd': 1}
方法一排序后: {'age': '18岁', 'city': '深圳', 'name': '张三', 'tel': '13626266627'}

方法二排序后: {'a': 4, 'b': 3, 'c': 2, 'd': 1}
方法二排序后: {'age': '18岁', 'city': '深圳', 'name': '张三', 'tel': '13626266627'}

方法三排序后: {'a': 4, 'b': 3, 'c': 2, 'd': 1}
方法三排序后: {'age': '18岁', 'city': '深圳', 'name': '张三', 'tel': '13626266627'}

方法四排序后: {'a': 4, 'b': 3, 'c': 2, 'd': 1}
方法四排序后: {'age': '18岁', 'city': '深圳', 'name': '张三', 'tel': '13626266627'}


总结下来,字典按照key排序的格式是:
dict(sorted(mydict.items()))
即,最外层是dict(),中间层是sorted(),最内层是被排序字典.items()
最终结果就是:dict(sorted(mydict.items())))


拓展:只要列表或者元祖中的元素,是成对儿出现的,都可以使用dict()将其转化成字典,例如:
列表: [['a', 1], ['b', 2], ('c', [4])]
列表转字典: {'a': 1, 'b': 2, 'c': [4]}
元组: (['a', 1], [('b',), 2], ('c', [4]))
元组转字典: {'a': 1, ('b',): 2, 'c': [4]}

方法五排序后: {'a': 4, 'b': 3, 'c': 2, 'd': 1}
方法五排序后: {'age': '18岁', 'city': '深圳', 'name': '张三', 'tel': '13626266627'}

从方法一到方法四
总结出字典排序的核心语句是:sorted(mydict.items())
而方法五的核心语句是:sorted(mydict.items(),key=lambda x:x[0])
在sorted()方法中添加了一个参数key,表示排序条件是lambda x:x[0]
解释:
匿名函数 lambda x:y 中x表示传入的参数,y表示lambda 函数的返回值
所以 lambda x:x[0] 表示传入参数x返回参数x的第一个元素,即x[0]
而字典的items()方法将字典的k和v转化为了元组,并且被当作参数传给了lambda的x
x的结构是(k,v),x[0]就是k,也就是用字典的key作为排序条件
为了更加方便的理解匿名函数lambda,可以改写成正常的函数, 并输出x、x[0]的结果和类型

x及x的类型到底什么: ('b', 3) <class 'tuple'>
x[0]及x[0]的类型到底什么: b <class 'str'>
x及x的类型到底什么: ('d', 1) <class 'tuple'>
x[0]及x[0]的类型到底什么: d <class 'str'>
x及x的类型到底什么: ('c', 2) <class 'tuple'>
x[0]及x[0]的类型到底什么: c <class 'str'>
x及x的类型到底什么: ('a', 4) <class 'tuple'>
x[0]及x[0]的类型到底什么: a <class 'str'>
方法五排序后: {'a': 4, 'b': 3, 'c': 2, 'd': 1}

x及x的类型到底什么: ('name', '张三') <class 'tuple'>
x[0]及x[0]的类型到底什么: name <class 'str'>
x及x的类型到底什么: ('age', '18岁') <class 'tuple'>
x[0]及x[0]的类型到底什么: age <class 'str'>
x及x的类型到底什么: ('city', '深圳') <class 'tuple'>
x[0]及x[0]的类型到底什么: city <class 'str'>
x及x的类型到底什么: ('tel', '13626266627') <class 'tuple'>
x[0]及x[0]的类型到底什么: tel <class 'str'>
方法五排序后: {'age': '18岁', 'city': '深圳', 'name': '张三', 'tel': '13626266627'}

从上面的输出结果可以看出x[0]就是字典的key值
按照字典的value排序:
排序后: {'d': 1, 'c': 2, 'b': 3, 'a': 4}
排序后: {'tel': '13626266627', 'age': '18岁', 'name': '张三', 'city': '深圳'}

按照value排序后发现“张三”在“深圳”前面
原因是python以较汉字的utf-8的编码值排序的
使用ord()方法可以得到汉族的Unicode编码(10进制)
ord('张')得出24352,ord('深')得出28145
所以‘张’排在‘深’前面
或者使用 '张'.encode() 得出E5BCA0,'深'.encode() 得出E6B7B1,比较16进制也能看出大小

字典嵌套字典,按照被嵌套字典的key排序,即abcd排序:
原始顺序: {'d': {'sort': 7}, 'a': {'sort': 3}, 'c': {'sort': 4}, 'b': {'sort': 1}}
按照key排序: {'a': {'sort': 3}, 'b': {'sort': 1}, 'c': {'sort': 4}, 'd': {'sort': 7}}
字典嵌套字典,按照被嵌套字典的value排序,即1347排序:
按照key排序: {'b': {'sort': 1}, 'a': {'sort': 3}, 'c': {'sort': 4}, 'd': {'sort': 7}}

为了方便理解,再次把lambda改写成正常的函数,并输出x[1]['sort']的值:
('d', {'sort': 7}) {'sort': 7} 7
('a', {'sort': 3}) {'sort': 3} 3
('c', {'sort': 4}) {'sort': 4} 4
('b', {'sort': 1}) {'sort': 1} 1
按照value排序: {'b': {'sort': 1}, 'a': {'sort': 3}, 'c': {'sort': 4}, 'd': {'sort': 7}}

{'sortd': 7} dict_values([7]) 7
{'sorta': 3} dict_values([3]) 3
{'sortc': 4} dict_values([4]) 4
{'sortb': 1} dict_values([1]) 1
按照value排序: {'b': {'sortb': 1}, 'a': {'sorta': 3}, 'c': {'sortc': 4}, 'd': {'sortd': 7}}

按照value排序: {'b': {'sortb': 1}, 'a': {'sorta': 3}, 'c': {'sortc': 4}, 'd': {'sortd': 7}}

困难版

上面都是直接排序字典, 如果数据是列表中包含多个字典, 例如:

li = [{'k': 1, 'v': 2}, {'k': 12, 'v': 222}, {'k': 13, 'v': 32}]

正常函数就是:

def my_sort(x):
    # print(x)
    return x.get('k')

按照key和value倒序就是:

print(sorted(li, key=my_sort, reverse=True))
print(sorted(li, key=lambda x: x.get('v'), reverse=True))

输出:

[{'k': 13, 'v': 32}, {'k': 12, 'v': 222}, {'k': 1, 'v': 2}]
[{'k': 12, 'v': 222}, {'k': 13, 'v': 32}, {'k': 1, 'v': 2}]

困难版Plus

列表中每个元素的key和value的值都不一样

li = [{'k1': 1, 'v1': 2}, {'k2': 12, 'v2': 222}, {'k3': 13, 'v2': 32}]

正常的函数就是:

def my_sort(x):
    # print(list(x.items()))
    return list(x.items())[0][1]

按照key和value倒序就是:

print(sorted(li, key=my_sort, reverse=True))
print(sorted(li, key=lambda x: list(x.items())[1][1], reverse=True))

输出:

[{'k3': 13, 'v2': 32}, {'k2': 12, 'v2': 222}, {'k1': 1, 'v1': 2}]
[{'k2': 12, 'v2': 222}, {'k3': 13, 'v2': 32}, {'k1': 1, 'v1': 2}]