sortにおけるkeyの使い方からpythonを浅く語る

5092 ワード

Pythonを使う時間も短くはありませんが、C++コードを書く思考でPythonを書くのは、スクリプト言語としてのメリットがないような気がします.以前LeetCodeを塗ったとき、自分のPythonコードはいつも長く、Pythonのコートを着たC++コードに似ていました(ここに置いて、再構築を続けています).
たぶんpythonは簡単だと思って、普段はこまごました勉強をしているだけで、他人のコードを読むこともなく、把握が足りないからだと思います.この間の面接を思い出して、面接官は私の履歴書を見てPythonに詳しいことを書いて、2つのPythonの質問をしました.
  • Pythonでよく使われる最適化テクニック(Pythonの実行効率を向上させることができるのは、アルゴリズムレベルを除く)
  • valueに従ってdictのkey-value値を小さいから大きいまで出力します.

  • 私は長いことためらっていたが、点に答えず、拒否された(後で整理した内容はここに置いた).恥を知り勇ましく、しばらくの間Pythonの再学習を経て、Pythonの強さと美しさを徐々に発見した.
    ソートから言え!
    プログラムではソート関数がよく使われ、Pythonはsortとsorted関数を提供し、その場でソートし、ソート後の新しい結果を返し、関数のプロトタイプは簡単です.
    sort([cmp[, key[, reverse]]])
    

    以下のように、自分が最も多く使用しています.
    >>> l = [43, 12, 4, 6]
    >>> l.sort()
    >>> l
    [4, 6, 12, 43]

    Pythonのシンプルさと優雅さを体現していると思われていたが、C++STLのように反復器の範囲を指定する必要はなく、sortに対する理解も止まった.その後、少し複雑なソートシーンに遭遇し、自分でGoogle-stackoverflow-Copyについて、目の前の問題を解決しましたが、深く掘り下げたことはありません(そのため、その面接で上記の2番目の質問に答えられませんでした).
    sortの美しさ
    後でsortの関数の説明を見て、cmp、key、reverseパラメータがどのように使われているのかを含めて、いくつかの例を書いて、これはsortに対して理解していると思っています.たとえば、値の大きさに応じて辞書の内容を出力する場合は、次のように優雅に解決できます.
    >>> d = {1: 'z', 2:'y', 3: 'x'}
    >>> print sorted(d.items(), key=lambda x: x[1])
    [(3, 'x'), (2, 'y'), (1, 'z')]

    valueに基づいて並べ替えられた辞書さえ手に入れることができます.collections.OrderedDictを使うだけでいいです.
    >>> from collections import OrderedDict
    >>> sorted_d = OrderedDict(sorted(d.items(), key=lambda x: x[1]))
    >>> sorted_d
    OrderedDict([(3, 'x'), (2, 'y'), (1, 'z')])

    sortの魅惑
    hackerrankでこの問題に遭遇するまでsortを理解するのに十分だと思っていました.
    大文字と小文字、数字のみを含む文字列を指定し、ソートします.
  • すべての小文字は大文字の前に
  • すべてのアルファベットは数字の前に
  • すべての奇数は偶数より前
  • 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におけるメタグループは比較可能)のような任意の比較可能なコンテンツであってもよい.上記のソートの問題は、次のコードで解決できます.
    >>> s = "Sorting1234"
    >>> "".join(sorted(s, key=lambda x: (x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x)))
    'ginortS1324'

    ここで,lambda関数は入力した文字を1つのメタグループに変換し,sorted (文字ではなく)比較し,各文字の前後順序を判断する.
    同じプログラムをC++で書くと、ソートのルールを定義する複雑なシミュレーション関数が必要になるかもしれませんが、Pythonほど簡潔で優雅ではありません.
    Pythonを探して
    Pythonは簡単で便利な言語で、ほとんどの人がPythonに対する第一感覚だと信じています.Pythonを初めて学ぶと、Pythonのリスト解析、listスライス、辞書の導出、あるいはネットワークライブラリrequests、科学コンピューティングライブラリnumpy、web開発フレームワークDjangoなど、さまざまな強力なサードパーティライブラリに夢中になる可能性があります.
    しかし、実際にプログラムを書くと、私たちはよくPythonコードをたくさん書きます.例えば、1つの数字が返信数字であるかどうかを判断するには、次のようなコードを習慣的に書く可能性があります.
    def isPalindrome(x):
        if x < 0:
            return False
        reversed_x = 0
        original_x = x
        while x > 0:
            reversed_x = reversed_x * 10 + x % 10
            x /= 10
        return reversed_x == original_x
    

    よく見ると、これはまるでC++コードで、Pythonの優雅さと簡単さは全くありません.では、どのようにして表示できるPythonicを書くのでしょうか.実は、Pythonを使えば1行でいいのです(ここでは効率を考えず、効率を考えればC++の方がしっくりくるのですが、この問題だけでは上より効率的な方法があります)!
    def isPalindrome(x):
        return x >= 0 and str(x) == str(x)[::-1]
    

    では、Pythonicの思考で問題を解決するにはどうすればいいのでしょうか.まずPythonに詳しいと思います.ほとんどの関数とPythonの特色に精通しています.例えば、装飾器、反復器、ジェネレータなどです.以下に簡単な例を挙げます.
    #      
    >>> nums = map(int, "123456789" )
    >>> nums
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
    15
    >>> sum(nums)
    45
    #    
    >>> mygenerator = (x*x for x in range(3))
    >>> for i in mygenerator:
    ...     print i
    ...
    0
    1
    4
    >>> for i in mygenerator:
    ...     print i
    ...
    # lambda     
    >>> c = lambda *z: z
    >>> c( 10, 'test')
    (10, 'test')
    #   
    >>> l = [i**2 for i in range(9)]
    >>> l_iter = iter(l)
    >>> next(l_iter)
    0
    >>> next(l_iter)
    1
    >>> next(l_iter)
    4
    #      set
    >>> set_a = set([i for i in range(1,9,2)])
    >>> set_b = set([i for i in range(0,9,2)])
    >>> print set_a | set_b
    set([0, 1, 2, 3, 4, 5, 6, 7, 8])

    次に、Pythonicのコードをもっと読んで、他人がpythonを優雅に使う方法を学びます.ここではLeetcodeのDiscussを見に行くことをお勧めします.中には驚くほど艶やかなコードがたくさんあります.特に@StefanPochmannをお勧めします.多くのコードは私にiter()の使用などの利益をもたらします.
    もう一つの問題は、32ビットの整形符号なし数字をバイナリビットで反転させることです.Pythonで簡単で直感的なコードを書くことができます.以下のようにします.
    def reverseBits(n):
        bit_str = '{0:032b}'.format(n)
        reverse_str = bit_str[::-1]
        return int(reverse_str, 2)
    

    もちろん、効率は考えられませんが、ここには分治法思想を利用した効率的な方法があります.
    Pythonは効率的で簡単で便利な言語ですが、時間をかけずに使えるという意味ではありません.
    その他の記事
    詳細
    Sorting Mini-How TO sort()におけるcmpパラメータの使い方hackerrank:ginortS Sort a Python dictionary by value Python高度なプログラミングテクニック