由 sort 中 key 的用法淺談 python

selfboot發表於2016-05-11

用 Python 時間也算不短了,但總感覺自己在用寫 C++ 程式碼的思維寫 Python,沒有真正用到其作為指令碼語言的優勢。之前刷 LeetCode 時,自己的 Python 程式碼總是很長,很像披著 Python 外衣的 C++ 程式碼(放在這裡,不斷重構中)。

想來大概是因為覺得python簡單,平時只是零零碎碎的學習,也沒有去讀別人的程式碼,導致掌握的不夠深入。回想起前段時間的面試,面試官看我簡歷寫熟悉Python,就問了兩個Python的問題:

  1. Python 中常用的優化技巧(能夠提升 Python 執行效率的,除了演算法層面)
  2. 按照 value 從小到大輸出 dict 中的 key-value值。

我支支吾吾半天,就是沒有答到點上,直接導致被拒(後來整理的內容放在這裡)。所謂知恥而後勇,經過一段時間對 Python 的重新學習,才慢慢發現 Python 的一些強大與美妙之處。

從排序說起!

程式中經常用到排序函式,Python 提供了 sort 和 sorted 函式,一個原地排序,一個返回排序後的新結果,函式原型很簡單:

自己用的最多的類似下面的語句:

曾經竊以為這就體現了 Python 的簡單優雅,不像 C++ STL中那樣還需要指定迭代器範圍,然後對 sort 的理解也就止步於此。後來遇到稍微複雜一點的排序場景,自己就 Google-Stackoverflow-Copy,解決了眼前的問題,但是從來沒有去深挖(這也就導致那次面試中中沒有回答出來上面的第二個問題)。

sort 之美

後來去看了下 sort 的函式說明,包括 cmp, key, reverse 引數究竟怎麼去用,又寫了幾個例子,以為這下子對 sort 可謂是理解透徹了。比如要要根據值的大小輸出字典內容,那麼就可以像下面這樣優雅地解決:

我甚至可以得到一個根據value排序的字典,只需要用 collections.OrderedDict 即可:

sort 之魅

我以為我對 sort 理解足夠了,直到在 hackerrank 遇到這個題目

給定一個只包含大小寫字母,數字的字串,對其進行排序,保證:

  • 所有的小寫字母在大寫字母前面
  • 所有的字母在數字前面
  • 所有的奇數在偶數前面

考慮用 sort 函式來完成排序。開始之前,再來看看文件對sort函式中key的說明:

key parameter to specify a function to be called on each list element prior to making comparisons. The value of the key parameter should be a function that takes a single argument and returns a key to use for sorting purposes.

通俗講,key 用來決定在排序演算法中 cmp 比較的內容,key 可以是任何可被比較的內容,比如元組(python 中元組是可被比較的)。所以上面的排序問題可以用下面的程式碼來解決:

這裡,lambda 函式將輸入的字元轉換為一個元組,然後 sorted 函式將根據元組(而不是字元)來進行比較,進而判斷每個字元的前後順序。

如果同樣的程式用 C++ 來寫的話,可能需要一個複雜的仿函式,來定義排序的規則,遠沒有 Python 這般簡潔優雅。

再探 Python

Python 是一門簡單方便的語言,相信這是大部分人對 Python 的第一感覺。初學 Python,我們可能痴迷於 Python 的列表解析,list 切片,字典推導,或者是陶醉在各種強大的第三方庫裡,比如網路庫 requests,科學計算庫 numpy,web開發框架 Django 等。

但是實際寫程式中,我們經常會寫出許多繁雜的、醜陋的Python程式碼。比如要判斷一個數字是否是迴文數字,可能會習慣性地寫出下面這樣的程式碼:

仔細一看,這簡直就是 C++ 程式碼,完全沒有 Python 的優雅與簡單。那麼,該怎樣寫才能夠顯的 Pythonic 呢?其實,用 Python 的話只要一行就可以啦(這裡不考慮效率,如果考慮效率的話,C++會更加合適,單對這題來說,其實有比上面更高效的方法)!

那麼如何養成用 Pythonic 的思維解決問題呢?我覺得首先要對 Python 十分熟悉,精通大部分函式以及 Python 的特色:比如裝飾器,迭代器,生成器以等,下面舉幾個簡單的例子:

其次,要多讀一些 Pythonic 的程式碼,學習別人如何優雅地使用python。這裡我推薦去看 Leetcode 的 Discuss,裡面有許多驚才豔豔的程式碼。特別推薦 @StefanPochmann,許多程式碼讓我獲益匪淺,比如這裡對 iter() 的使用。

再來看一個問題,按照二進位制位反轉 32 位的一個整形無符號數字。用 Python 可以寫出很簡單直觀的程式碼,如下:

當然,上面不考慮效率,這裡有一個利用分治法思想的高效的方法。

Python 是一門高效、簡單、方便的語言,但這並不意味你不花時間就可以用的很好。

更多閱讀

Sorting Mini-HOW TO
sort()中cmp引數的用法
hackerrank: ginortS
Sort a Python dictionary by value
Python高階程式設計技巧

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

由 sort 中 key 的用法淺談 python 由 sort 中 key 的用法淺談 python

相關文章