Python プログラミングにおける 3 つの一般的なデータ構造とアルゴリズム

Python プログラミングにおける 3 つの一般的なデータ構造とアルゴリズム

Python には、リスト、セット、辞書など、非常に便利な組み込みデータ構造が多数あります。ほとんどの場合、これらのデータ構造を直接使用できます。ただし、通常は、検索、並べ替え、配置、フィルタリングなどの一般的な問題も考慮する必要があります。

この記事では、3 つの一般的なデータ構造とデータ関連のアルゴリズムを紹介します。さらに、コレクション モジュールには、さまざまなデータ構造のソリューションも含まれています。

[[262323]]

1. 系列を個別の変数に分解する

(1)問題点

N 個の要素を含むタプルまたはシーケンスがあり、それを N 個の個別の変数に分解したいと考えています。

(2)解決策

任意のシーケンス (または反復可能なオブジェクト) は、単純な代入操作で個別の変数に分割できます。 1 つの要件は、変数の合計数と構造がシーケンスのものと一致することです。例えば:

  1. > > >   p = (4, 5)
  2. >>> x , y = p  
  3. > > > ×
  4. 4
  5. > > >はい
  6. 5
  7. > > >  
  8. > > >  データ= [ 'ACME', 50, 91.1, (2012, 12, 21) ]
  9. > > >名前、株数、価格、日付=データ 
  10. > > >名前
  11. 「アクメ」
  12. > > >日付
  13. (2012年12月21日)
  14. > > >名前、株数、価格、(年、月、日)=データ
  15. > > >名前
  16. 「アクメ」
  17. > > >
  18. 2012
  19. > > >月曜日
  20. 12
  21. > > >
  22. 21
  23. > > >  

要素数が一致しない場合はエラーが発生します。例えば:

  1. > > >   p = (4, 5)
  2. >>> x , y, z = p  
  3. トレースバック(最新の呼び出しが最後):
  4. ファイル " < stdin > "、行 1、 < module >  
  5. ValueError: 解凍するには 2 つ以上の値が必要です
  6. > > >  

(3)議論

実際、タプルやリストだけでなく、オブジェクトが反復可能である限り、分解操作を実行できます。これには、文字列、ファイル、反復子、ジェネレーターが含まれます。例えば:

  1. > > >   s = 'こんにちは'  
  2. > > > a、b、c、d、 e = s  
  3. > > >
  4. 「は」
  5. > > >
  6. 'え'
  7. > > > e
  8. 「お」
  9. > > >  

分解操作を行うときに、特定の値を破棄したい場合があります。 Python ではこれを行うための特別な構文は提供されていませんが、通常は、破棄する値の名前として未使用の変数名を選択できます。例えば:

  1. > > >  データ= [ 'ACME', 50, 91.1, (2012, 12, 21) ]
  2. > > > _、株、価格、 _ =データ 
  3. > > >シェア
  4. 50
  5. > > >価格
  6. 91.1
  7. > > >  

ただし、他の場所で使用されていない変数名を選択するようにしてください。

2. 任意の長さの反復可能オブジェクトの要素を分解する

(1)問題点

反復可能オブジェクトから N 個の要素をアンパックする必要がありますが、反復可能オブジェクトの長さが N を超える場合があり、「アンパックする値が多すぎます」という例外が発生します。

(2)解決策

この問題を解決するには、Python の「* 式」を使用できます。たとえば、あるコースが提供され、最終成績から最初と最後の課題を削除し、残りの中間の成績のみを平均することにしたとします。グレードが 4 つしかない場合は、単純に 4 つすべてを因数分解できるかもしれませんが、24 あった場合はどうなるでしょうか。 * 式を使用すると、すべてが簡単になります。

  1. def drop_first_last(成績):
  2. 1、*中間、最終=成績 
  3. 平均(中央)を返す

もう 1 つの使用例としては、名前と電子メール アドレス、それに続く任意の数の電話番号で構成されるユーザー レコードがいくつかあると想定します。次に、レコードを次のように分解します。

  1. > > >  レコード= ('Dave', '[email protected]', '773-555-1212', '847-555-1212')
  2. > > >名前、メールアドレス、*電話番号=ユーザーレコード 
  3. > > >名前
  4. 「デイブ」
  5. > > >メール
  6. '[email protected]'
  7. > > >電話番号
  8. ['773-555-1212', '847-555-1212']
  9. > > >  

いくつの電話番号を因数分解する必要があるかに関係なく (または電話番号がない場合でも)、変数 phone_numbers は常にリストになり、意味がありません。そうすれば、変数 phone_numbers を使用するコードは、それがリストではないかもしれないという事実を心配する必要がなくなり、追加の型チェックを行う必要もなくなります。

* で変更された変数は、リストの最初の位置に置くこともできます。たとえば、過去 8 四半期の会社の売上を表す一連の値があるとします。直近の四半期の売上を過去 7 四半期の平均と比較する場合は、次のようにします。

  1. *trailing_qtrs、 current_qtr =売上記録 
  2. 後続平均=合計(後続四半期) / 長さ (後続四半期)
  3. avg_comparison(trailing_avg, current_qtr) を返します。

Python インタープリターの観点から見ると、この操作は次のようになります。

  1. > > > *末尾、現在= [10, 8, 7, 1, 9, 5, 10, 3]
  2. > > >末尾
  3. [10、8、7、1、9、5、10]
  4. > > >現在
  5. 3

(3)議論

この拡張分解操作は、長さが不明または任意の反復可能なオブジェクトを分解するためのカスタム ツールです。多くの場合、このような反復可能オブジェクトには既知のコンポーネントまたはパターンがあり (たとえば、要素 1 の後はすべて電話番号です)、* 式を使用して反復可能オブジェクトを分解すると、開発者は関連する要素を取得するために反復可能オブジェクト内で複雑な操作を実行する必要なく、これらのパターンを簡単に利用できます。

* スタイルの構文は、可変長のタプルのシーケンスを反復処理する場合に特に便利です。たとえば、ラベル付きタプルのシーケンスがあるとします。

  1. レコード= [
  2. ('foo', 1, 2),
  3. (「バー」、「こんにちは」)、
  4. ('foo', 3, 4),
  5. ]
  6. do_foo(x, y)を定義します。
  7. print('foo', x, y)
  8. def do_bar(s):
  9. 印刷('bar', s)
  10. タグの場合、レコード内の*引数:
  11. タグ== 'foo' の場合:
  12. do_foo(*引数)
  13. elifタグ== 'bar':
  14. do_bar(*引数)

この * スタイルの構文でサポートされている分解操作は、分割などの特定の文字列処理操作と組み合わせた場合にも非常に便利です。例えば:

  1. > > >  = 'nobody:*:-2:-2:権限のないユーザー:/var/empty:/usr/bin/false'  
  2. > > > uname、*fields、homedir、 sh =.split(':')
  3. > > >名前なし
  4. '誰でもない'
  5. > > >ホームディレクトリ
  6. '/var/空'
  7. > > >シュ
  8. '/usr/bin/偽'
  9. > > >  

場合によっては、特定の値を除外して破棄したい場合があります。分解する際には、* を一つだけ指定するのではなく、_ や ign (無視) など、破棄する値を表すためによく使われる変数名を複数使用することができます。例えば:

  1. > > >  レコード= ('ACME', 50, 123.45, (12, 18, 2012))
  2. > > >名前、*_、(*_、年) = レコード
  3. > > >名前
  4. 「アクメ」
  5. > > >
  6. 2012
  7. > > >  

*分解操作は、さまざまな関数型言語のリスト処理関数とある程度類似しています。たとえば、リストがある場合、次のように簡単に先頭と末尾に分解できます。

  1. > > >  アイテム= [1, 10, 7, 4, 5, 9]
  2. > > >ヘッド、*テール=アイテム 
  3. > > >
  4. 1
  5. > > >しっぽ
  6. [10、7、4、5、9]
  7. > > >  

この種の分割機能を実行する関数を作成する場合、何らかの高度な再帰アルゴリズムを実装することを意図していると思われるかもしれません。例えば:

  1. >>> def sum (items) :
  2. ... ヘッド、*テール=アイテム 
  3. ... 末尾の場合は head + sum(tail) を返し、それ以外の場合は head を返します
  4. ...
  5. > > >合計(アイテム)
  6. 36
  7. > > >  

ただし、再帰は固有の制限があるため、Python の強みではないことに注意してください。したがって、この最後の例には実用的な意味はあまりなく、単なる学術的な好奇心によるものです。

3. 最後のN要素を保存する

(1)問題点

反復処理やその他の形式の処理中に、最後のいくつかのレコードの限定的な履歴記録を作成したいと考えています。

(2)解決策

限定された履歴レコードを保存することは、collections.deque のアプリケーション シナリオと見なすことができます。たとえば、次のコードは、一連のテキスト行に対して単純なテキスト マッチング操作を実行します。一致が見つかると、現在の一致行とチェックされたテキストの最後の N 行を出力します。

  1. コレクションから deque をインポート
  2. def search(行、パターン、履歴= 5 ):
  3. previous_lines = deque ( maxlen = history )
  4. 行内の行の場合:
  5. パターンが行内にある場合:
  6. 譲歩ライン、前の行
  7. previous_lines.append(行)
  8. # ファイルでの使用例
  9. __name__ == '__main__' の場合:
  10. open('somefile.txt') を f として実行します:
  11. 行に対して、prevlines in search(f, 'python', 5):
  12. prevlines の pline の場合:
  13. print(ポリライン、終了= '' )
  14. print(行,終了= '' )
  15. 印刷('-'*20)

(3)議論

上記のコード スニペットのように、レコードを検索するコードを記述する場合、通常は yield キーワードを含むジェネレーター関数を使用します。これにより、検索を処理するコードと検索結果を使用するコードが適切に分離されます。ジェネレーターに慣れていない場合は、セクション 4.3 を参照してください。

deque(maxlen=N) は固定長のキューを作成します。新しいレコードが追加され、キューがいっぱいになると、最も古いレコードが自動的に削除されます。例えば:

  1. > > >   q =デキュー(最大長= 3 )
  2. > > > q.append(1)
  3. > > > q.append(2)
  4. > > > q.append(3)
  5. > > >質問
  6. デキュー([1, 2, 3],最大長= 3 )
  7. > > > q.append(4)
  8. > > >質問
  9. デキュー([2, 3, 4],最大長= 3 )
  10. > > > q.append(5)
  11. > > >質問
  12. deque([3, 4, 5],最大長= 3 )

このような操作 (追加、削除) はリストに対して手動で実行できますが、キュー ソリューションの方がはるかに洗練されており、実行速度もはるかに速くなります。

より一般的には、単純なキュー構造が必要な場合、 deque が役立ちます。キューのサイズを指定しない場合は、無制限のキューが取得され、両端で操作の追加とポップを実行できます。次に例を示します。

  1. > > >   q =デキュー()
  2. > > > q.append(1)
  3. > > > q.append(2)
  4. > > > q.append(3)
  5. > > >質問
  6. デキュー([1, 2, 3])
  7. > > > q.appendleft(4)
  8. > > >質問
  9. デキュー([4, 1, 2, 3])
  10. > > > q.pop()
  11. 3
  12. > > >質問
  13. デキュー([4, 1, 2])
  14. > > > q.popleft()
  15. 4

キューのどちらかの端から要素を追加またはポップする複雑さは O(1) です。これは、リストの先頭に要素を挿入したり削除したりする場合の複雑さが O(N) であるリストとは異なります。

<<:  データサイエンスと機械学習のためのトップ 16 プラットフォーム

>>:  2019年の人工知能の開発動向

ブログ    
ブログ    
ブログ    
ブログ    

推薦する

認知グラフは人工知能の次の大きなトレンド

AIの次のチャンスはどこにあるのでしょうか? AIの概念が初めて提唱されたのは1956年なので、60...

...

企業内で AI 分析を導入し拡張する方法

[[415863]]多くの組織の AI 分析に対する要望と、組織の規模や能力との間のギャップは拡大し...

睡眠研究はより優れた AI モデルの作成に役立ちますか?

私たちはなぜ眠るのでしょうか? 明らかな理由の一つは、体と手足の力を回復することです。しかし、睡眠の...

...

AWS は、機械学習の経験がなくても、企業の日常業務を改革し改善する 5 つの新しい機械学習サービスを開始しました。

Amazon Kendra は、自然言語処理やその他の機械学習技術を使用してエンタープライズ検索を...

...

エージェントは人間のように協力し、「グループチャット」を通じて情報を交換することができます。

インテリジェントエージェントにも「標準マニュアル」が必要です。 MetaGPTと呼ばれる研究では、イ...

トレンド | AIを学ぶには、まず2018年の人工知能に関する13の予測を理解する必要があります

[[214541]] 2017 年は、ウォール ストリート ジャーナル、フォーブス、フォーチュンなど...

ブロックチェーンにおける主流のコンセンサスアルゴリズムの簡単な分析

プルーフ・オブ・ワーク最も一般的なブロックチェーンのコンセンサス アルゴリズムは、ビットコインのプル...

機械学習を簡単に理解!クラスタリング、回帰、分類アルゴリズムを説明する 3 つのケース

機械はどのように学習し、何を学ぶのでしょうか?人間はどうやって機械に学習を教えるのでしょうか?この記...

...

セマンティックAIとデータ管理の5つのトレンド

1. グラフデータベースとナレッジグラフが2022年に主流になる グラフ データベースが 2022 ...

...

AIoT技術の幅広い応用と大きな利点

比較的新しい概念である AIoT は、人工知能 (AI) とモノのインターネット (IoT) を組み...