Pythonで配列をシャッフルする方法:shuffle()とreset()の実装解説
はじめに
配列Aが与えられたとき、重複のない数値の集合をシャッフルすることを考えます。例えば、入力が [1,2,3] の場合、シャッフルを実行すると [1,3,2] となり、リセット後に再度シャッフルすると [2,3,1] のようになります。
この問題を解決するために、__init__()、reset()、shuffle() という3つのメソッドを持つクラスを設計します。それぞれの動作は以下の通りです。
アルゴリズムの設計
init(コンストラクタ)の処理
original := 与えられた配列のコピーを保持する
temp := 元の配列 nums をそのまま格納する
indices := 0 から nums の長さ - 1 までのインデックスのリストを作成する
reset() メソッドの処理
reset() を呼び出すと、元の配列 original を返します。
shuffle() メソッドの処理
temp の長さが 0 の場合は、空の配列を返します。
i := indices 配列からランダムに1つのインデックスを選択し、j := 同様にもう1つのインデックスをランダムに選択します。
インデックス i と j の位置にある要素を入れ替えます。
temp を返します。
補足:全順列を生成する別のアプローチ
もう一つの方法として、getAllPermutation() というメソッドを使ってすべての順列を生成することもできます。引数として nums と i を受け取り、初期値は i = 0 とします。処理の流れは以下の通りです。
curr := i とします。
i が nums の長さと等しい場合:
nums 配列のコピーを all という配列に挿入します。
処理を終了して戻ります。
j を curr から nums の長さまでループさせます:
nums のインデックス j と curr の要素を入れ替えます。
getAllPermutation(nums, curr + 1) を再帰的に呼び出します。
nums のインデックス j と curr の要素を再度入れ替えて元に戻します(バックトラック)。
実装例
以下の実装を見ると、より理解しやすくなります。
import random
class Solution(object):
def __init__(self, nums):
self.original = [x for x in nums]
self.temp = nums
self.indices = [x for x in range(len(nums))]
def reset(self):
return self.original
def shuffle(self):
if not len(self.temp):
return []
i = random.choice(self.indices)
j = random.choice(self.indices)
self.temp[i], self.temp[j] = self.temp[j], self.temp[i]
return self.temp
ob = Solution([1,2,3])
print(ob.shuffle())
print(ob.reset())
print(ob.shuffle())
入力
[1,2,3] で初期化した後、shuffle()、reset()、shuffle() の順に呼び出す
出力
[2, 1, 3] [1, 2, 3] [2, 3, 1]
まとめ
この実装では、元の配列をコピーとして保持しておくことで、いつでも reset() で初期状態に戻せるのがポイントです。また、shuffle() では random.choice() を使って2つのランダムなインデックスを選び、要素を入れ替えることでシャッフルを実現しています。なお、実務でより均等なシャッフルが必要な場合は、Python標準ライブラリの random.shuffle() を利用するのも有効です。
-
Pythonの継承とは?単一継承と階層継承の基本をサンプルコードで解説
本記事では、Python 3.xにおける継承(インヘリタンス)とクラスの拡張方法について詳しく解説します。 継承とは、現実世界のモノや概念の関係性を自然に表現できる、オブジェクト指向プログラミングの中核となる仕組みです。継承を活用すると、次のようなメリットが得られます。 再利用性:すでに書いたコードを流用でき、重複を削減できる 推移性:クラス間の関係を連鎖的に引き継げる 開発速度の向上:ゼロから書かずに済むため、短期間で開発できる 保守性・拡張性:既存クラスを壊さずに機能を追加しやすい 継承の5つの種類 Pythonの継承は、その構造によって主に以下の5種類に分類されます。 単一継承(
-
Pythonの代表的な例外(Exception)の種類と発生原因をコード例付きで解説
Pythonには、プログラムの中で頻繁に発生する代表的な例外がいくつか存在します。これらの例外は、プログラマが明示的に発生させる場合もあれば、Pythonインタプリタが暗黙的に検出して発生させる場合もあります。ここでは、特によく見かける主要な例外について、その発生条件と実際のコード例・実行結果を交えて詳しく解説します。 AssertionError(アサーションエラー) assert文の条件が偽(False)になった場合に発生する例外です。Pythonではコード内にassert文を記述でき、その条件は常に真であることが期待されます。条件が満たされなかった瞬間にAssertionErrorが送出