概要
sorted
関数を利用することで、 DBアクセスする回数を減らすことができましたので紹介します。
サンプルコード1
sorted
関数とは、イテラブル(リスト、タプル、辞書など)をソートした新しいリストを返す関数。
以下、シンプルなサンプルコードです。
def sort_and_tuple(input_list):
sorted_tuple = tuple(sorted(input_list))
return sorted_tuple
my_list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
result = sort_and_tuple(my_list)
print(result) # (1, 1, 2, 3, 3, 4, 5, 5, 5, 6, 9)
sort_and_tuple
関数は、入力としてリストを受け取り、そのリストをソートした後、タプルに変換して返します。このように、sorted
関数とtuple
関数を組み合わせることで、リストの要素をソートし、その結果を変更不可能なタプルとして保存することができます。
公式ドキュメントはこちら。
サンプルコード2
次に、fruit_list1
とfruit_list2
という、異なる順序で同じ要素を持つリストで利用したコードです。
以下の通り、それぞれ別の順番ですが、ソートされたことで、これらのリストは関数内で「辞書のキー」として同じとみなされています。
def add_to_dict(input_list, value, my_dict):
sorted_tuple = tuple(sorted(input_list))
my_dict[sorted_tuple] = value
my_dict = {}
fruit_list1 = ['apple', 'banana', 'cherry']
value1 = "Fruit Salad"
fruit_list2 = ['cherry', 'banana', 'apple']
value2 = "Smoothie"
add_to_dict(fruit_list1, value1, my_dict)
add_to_dict(fruit_list2, value2, my_dict)
print(my_dict) # {('apple', 'banana', 'cherry'): 'Smoothie'}
最後に追加された値がSmoothie
なので、Smoothie
だけが保持されていることがわかりますね。
異なる順序で同じ要素を持つリストが同じキーとして扱われたことが確認できました。
サンプルコード3
もう一つレベルアップして、冒頭で紹介した、DBアクセスを減らせる方法を紹介します。
もしも、順番が異なるだけの同じ組み合わせのクエリを(for
ループとかで)大量にDBアクセスしている場合、少しパフォーマンスに影響が出てしまいますよね。その場合、以下のように、sorted
でまずはソートし、一度同じ組み合わせで取得したものは辞書に保存(キャッシュ)してあげる形にします。
class DataFetcher:
def __init__(self):
self.data_cache = {}
def get_data(self, list1, list2, list3):
key = (tuple(sorted(list1)), tuple(sorted(list2)), tuple(sorted(list3)))
# キーが辞書に存在しない場合は、データを取得する
if key not in self.data_cache:
self.data_cache[key] = SampleModel.objects.filter(
Q(field1__in=list1) & Q(field2__in=list2) & Q(field3__in=list3)
).distinct()
return self.data_cache[key]
この例では、get_data
メソッド内でSampleModel
からデータを取得し、それをキャッシュに保存します。実際にこのようにすることで、同じ組み合わせのクエリ実行が大幅に減りました。
ちなみに、Q
オブジェクトは、複数のフィールドに対する複雑なクエリを作成するためのもの。
上記では、
field1
がlist1
のいずれかの値を持ち、
field2
がlist2
のいずれかの値を持ち、
field3
がlist3
のいずれかの値を持つ、
すべてのSampleModel
オブジェクトを取得するコードになっています。
sorted
メソッドもある
ちなみに、sorted
関数とは別でsorted
メソッドがあります。
numbers = [5, 2, 3, 1, 4]
numbers.sort()
print(numbers) # [1, 2, 3, 4, 5]
これはリスト自体をソートするリストオブジェクトのメソッド。
こちらの場合は、新しいリストを返さず、元のリストを直接変更します。