说起怎么排序Python,这事儿嘛,用Python时间久了,谁还没遇上几次要给东西排队的情况?列表、字典、自定义对象,大大小小,总得有个先来后到。别以为这简简单单一个“排序”,里头学问还真不少,要是用不好,效率那叫一个惨不忍睹,代码写出来也像一坨浆糊。今儿个,咱就掰扯掰扯,在Python里到底怎么排序这档子事儿。
你刚上手Python,可能最先接触的就是列表(List)。列表排序,这太直观了不是?Python给你准备了个现成的招儿:list.sort()
方法。瞧,直接在列表对象上调用,它就“原地”给你排好了。比如你有个数字列表 nums = [3, 1, 4, 1, 5, 9, 2, 6]
,想让它从小到大,直接 nums.sort()
走你!再打印 nums
,嘿,[1, 1, 2, 3, 4, 5, 6, 9]
,齐活!想倒着排?简单,nums.sort(reverse=True)
,参数一设,分分钟给你来个逆序。
但等等,这个 sort()
方法,它有个脾气——它是“就地”排序,也就是说,它会直接修改原列表,不给你留个副本。有时候,你可能不希望动原列表,就想拿个排好序的新列表接着用,原列表该是啥样还是啥样。这时候,Python又给你准备了另一招:内置函数 sorted()
。这个 sorted()
就乖巧多了,它不挑食,列表、元组、字符串,甚至字典、集合这些迭代对象它都能给你排。最关键的是,它不改变原对象,总是返回一个全新的、排好序的列表。
打个比方,你有个元组 data = (5, 2, 8, 1, 9)
,元组是不可变的,你不能直接调用 sort()
。但你可以 sorted_data = sorted(data)
。看看 data
,还是 (5, 2, 8, 1, 9)
,纹丝不动;而 sorted_data
呢,赫然是一个崭新的列表 [1, 2, 5, 8, 9]
。看到了吧?一个原地修改,一个返回新列表,这俩哥们儿各有各的用武之地,得看你具体的场景选谁。
那要是排序的不是简单的数字或者字符串呢?比如你有一个列表,里面装的是各种商品信息,每个商品是个字典,长这样:products = [{'name': 'Laptop', 'price': 8000, 'stock': 50}, {'name': 'Keyboard', 'price': 500, 'stock': 200}, {'name': 'Mouse', 'price': 200, 'stock': 150}]
。现在你想按价格从低到高排序,怎么排序Python这个列表里的字典?直接 sorted(products)
肯定不行,Python不知道该拿字典的哪个部分来比。
这时候,就需要请出 key
参数了。无论是 sort()
方法还是 sorted()
函数,都有个 key
参数,它接收一个函数作为参数。这个函数会作用于列表中的每一个元素,然后排序的时候,就根据这个函数返回的值来比较大小。
要按价格排?没问题!我们可以写个小函数,接收一个商品字典,返回它的价格:def get_price(item): return item['price']
。然后调用 sorted(products, key=get_price)
。瞧,输出的就是按价格排好序的列表了。
等等,每次都得专门写个小函数给 key
,是不是有点麻烦?Python还有更优雅的方式——Lambda表达式。Lambda表达式就是个匿名的小函数,写起来更简洁。上面的例子用Lambda可以这么写:sorted(products, key=lambda item: item['price'])
。哎呀,是不是瞬间觉得代码清爽多了?Lambda表达式在这里简直是神器,随用随写,不用定义具名函数,特别适合这种一次性的简单操作。
要是我想先按价格排,价格一样的再按库存排呢?怎么排序Python能实现多级排序?这也能办到!key
函数不仅仅能返回一个值,它还能返回一个元组。Python在比较元组的时候,会先比较第一个元素,第一个元素相等再比较第二个,以此类推。所以,要先按价格升序,再按库存降序(库存多的排前面),我们可以让 key
函数返回 (价格, -库存)
。为啥是 -库存
呢?因为默认是升序,要降序就得取个负号,让大的变成小的,小的变成大的,这样升序排序时,原本大的反而会排在前面。
来,看看代码:sorted(products, key=lambda item: (item['price'], -item['stock']))
。这行代码就告诉你怎么排序Python实现多级排序了。它会先看价格,价格低的在前;如果价格一样,就看库存的负值,负值大的(也就是库存少的)反而排在后面,负值小的(也就是库存多的)排在前面,这不就实现了库存的降序排列嘛!妙不妙?
除了列表里的字典,你可能还会遇到给字典本身排序的情况。比如一个字典 scores = {'Alice': 85, 'Bob': 92, 'Charlie': 78, 'David': 92}
。字典本身是无序的(在Python 3.7+版本后,字典保持插入顺序,但这不叫排序),你想按分数高低,或者按名字字母顺序来处理这个字典。
记住,字典本身是无序集合,你不能直接对字典进行排序。但是,你可以获取字典的键(keys)、值(values)或者键值对(items),然后对这些列表进行排序,最后再根据排好的顺序来处理字典的数据。
比如,你想按分数高低获取名字列表。你可以这么干:sorted(scores, key=lambda name: scores[name], reverse=True)
。这里 sorted()
作用于字典的键(默认行为),key
函数则根据键去字典里查找对应的值(分数)来作为排序依据。reverse=True
表示降序,也就是分数高的在前。这样你就得到一个按分数从高到低排列的名字列表:['Bob', 'David', 'Alice', 'Charlie']
。你看,分数都是92的Bob和David,谁在前谁在后?这取决于原始字典中它们的相对位置(对于3.7+),或者是不确定顺序(对于3.6-)。
如果你想获得一个按分数排序后的键值对列表,方便后续处理,可以对 scores.items()
进行排序。scores.items()
会返回一个包含所有键值对的列表,每个键值对是一个元组 (键, 值)
。
sorted(scores.items(), key=lambda item: item[1], reverse=True)
。这里的 key
函数 lambda item: item[1]
表示用元组的第二个元素(也就是分数)来排序。结果会是一个列表,长这样:[('Bob', 92), ('David', 92), ('Alice', 85), ('Charlie', 78)]
。这下,按分数高低排好的键值对就一目了然了。
再多说一句,关于性能。对于简单的数字或字符串排序,Python内置的排序算法(Timsort,一种混合排序算法)效率非常高,通常情况下你不需要过度担心性能问题。但如果你的列表非常大,或者 key
函数的计算成本很高,那么性能就可能成为一个考虑因素。不过对于绝大多数日常开发来说,直接使用 sort()
或 sorted()
配合 key
参数已经绰绰有余了。
理解怎么排序Python的核心在于掌握 sort()
和 sorted()
的区别,以及如何灵活运用 key
参数。key
参数就像是给排序算法指路,告诉它“别看元素本身长啥样,就看我key函数算出来的值!” 这个“看”的方式决定了排序的结果。学会用Lambda表达式配合 key
参数,能让你的代码更紧凑,更具Pythonic风格。
总而言之,Python在排序这事儿上给的选择挺多,从最简单的原地排序 sort()
到返回新列表的 sorted()
,再到用 key
参数玩转各种复杂对象的排序,甚至是多级排序,它都给你安排得明明白白。所以下次再问怎么排序Python某个对象,先想想它是啥类型,想原地改还是拿新列表,需要基于啥规则排序,然后对号入座,用合适的工具和方法,写出既正确又漂亮的排序代码吧。熟练掌握这些,你的Python功力肯定噌噌往上涨。
评论(0)