Python でのカスタムソートに lambda 関数を使用する方法

PythonBeginner
オンラインで実践に進む

はじめに

Python の lambda 関数は、カスタムソート操作を実行するための簡潔で強力な方法を提供します。このチュートリアルでは、lambda 関数を使用して Python でデータをソートする方法を探求し、データ操作と分析の新たな可能性を解き放ちます。最終的には、カスタムソートに lambda 関数を活用することについて確固たる理解が得られ、これらのテクニックを独自の Python プロジェクトに適用できるようになります。

Lambda 関数の理解

Python では、lambda 関数は lambda キーワードで定義される、小さな無名関数です。 def キーワードを使用する通常の関数とは異なり、lambda 関数はインラインで作成でき、個別の定義は必要ありません。

lambda 関数を探求するために、新しい Python ファイルを作成しましょう。WebIDE を開き、/home/labex/project/lambda_sorting ディレクトリに basic_lambda.py という名前の新しいファイルを作成します。

basic_lambda.py に次のコードを追加します。

## 通常の関数を定義する
def square_function(x):
    return x * x

## 同等の lambda 関数
square_lambda = lambda x: x * x

## 両方の関数をテストする
number = 5
print(f"通常の関数を使用:{number}² = {square_function(number)}")
print(f"lambda 関数を使用:{number}² = {square_lambda(number)}")

## 複数の引数を持つ lambda
add = lambda x, y: x + y
print(f"{3} + {4} = {add(3, 4)}")

次に、このファイルをターミナルで実行します。

python3 basic_lambda.py

次のような出力が表示されるはずです。

通常の関数を使用: 5² = 25
lambda 関数を使用: 5² = 25
3 + 4 = 7

lambda 関数は、特に map()filter()、または sorted() のような関数を使用する場合など、短期間だけ単純な関数が必要な場合に特に役立ちます。 map() 関数で lambda を実際に使用する例をもう一つ作成しましょう。

次の内容で lambda_with_map.py という名前の新しいファイルを作成します。

## map() と lambda を使用して、リスト内のすべての項目に関数を適用する
numbers = [1, 2, 3, 4, 5]

## lambda 関数と map を使用してすべての数値を二乗する
squared_numbers = list(map(lambda x: x * x, numbers))

print(f"元の数値:{numbers}")
print(f"二乗された数値:{squared_numbers}")

## lambda 関数と map を使用してすべての数値を 2 倍にする
doubled_numbers = list(map(lambda x: x * 2, numbers))
print(f"2 倍された数値:{doubled_numbers}")

このファイルを実行します。

python3 lambda_with_map.py

次のように表示されるはずです。

元の数値: [1, 2, 3, 4, 5]
二乗された数値: [1, 4, 9, 16, 25]
2 倍された数値: [2, 4, 6, 8, 10]

lambda 関数をソートに適用する前に、lambda 関数を理解することが不可欠です。次のステップでは、Python のソート関数で lambda 関数を使用する方法を探求します。

Lambda 関数を使用した基本的なソート

Python には、コレクションをソートするための主な方法が 2 つあります。sorted() 関数と、リストの .sort() メソッドです。カスタムソートロジックを作成するために、両方で lambda 関数を使用できます。

lambda 関数を使用した基本的なソートを探求するために、basic_sorting.py という名前の新しいファイルを作成しましょう。

## 基本的なソートの例
fruits = ["apple", "banana", "cherry", "date", "elderberry", "fig"]

## アルファベット順にソート (デフォルトの動作)
alphabetical = sorted(fruits)
print(f"アルファベット順:{alphabetical}")

## lambda 関数を使用して長さでソート
by_length = sorted(fruits, key=lambda x: len(x))
print(f"長さでソート:{by_length}")

## 最後の文字でソート
by_last_char = sorted(fruits, key=lambda x: x[-1])
print(f"最後の文字でソート:{by_last_char}")

## 逆順にソート (最も長いものから短いものへ)
longest_first = sorted(fruits, key=lambda x: len(x), reverse=True)
print(f"最も長いものから短いものへ:{longest_first}")

このファイルを実行します。

python3 basic_sorting.py

次のような出力が表示されるはずです。

アルファベット順: ['apple', 'banana', 'cherry', 'date', 'elderberry', 'fig']
長さでソート: ['fig', 'date', 'apple', 'cherry', 'banana', 'elderberry']
最後の文字でソート: ['banana', 'apple', 'date', 'fig', 'cherry', 'elderberry']
最も長いものから短いものへ: ['elderberry', 'banana', 'cherry', 'apple', 'date', 'fig']

sorted()key パラメータは、比較前に各項目を変換する関数を受け取ります。Lambda 関数は、これらの変換を作成するための簡潔な方法を提供します。

次に、より複雑なデータ構造でのソートを試してみましょう。sorting_tuples.py というファイルを作成します。

## タプルのリストのソート
students = [
    ("Alice", 21, 85),
    ("Bob", 19, 90),
    ("Charlie", 22, 78),
    ("David", 20, 92),
    ("Eve", 18, 88)
]

print("元の学生データ:")
for student in students:
    print(f"  {student[0]}: age {student[1]}, grade {student[2]}")

## 名前でソート (タプルの最初の要素)
by_name = sorted(students, key=lambda student: student[0])
print("\n名前でソート:")
for student in by_name:
    print(f"  {student[0]}: age {student[1]}, grade {student[2]}")

## 年齢でソート (2 番目の要素)
by_age = sorted(students, key=lambda student: student[1])
print("\n年齢でソート:")
for student in by_age:
    print(f"  {student[0]}: age {student[1]}, grade {student[2]}")

## 成績でソート (3 番目の要素)
by_grade = sorted(students, key=lambda student: student[2], reverse=True)
print("\n成績でソート (最高から最低へ):")
for student in by_grade:
    print(f"  {student[0]}: age {student[1]}, grade {student[2]}")

このファイルを実行します。

python3 sorting_tuples.py

学生がさまざまな方法でソートされているのがわかるはずです。

元の学生データ:
  Alice: age 21, grade 85
  Bob: age 19, grade 90
  Charlie: age 22, grade 78
  David: age 20, grade 92
  Eve: age 18, grade 88

名前でソート:
  Alice: age 21, grade 85
  Bob: age 19, grade 90
  Charlie: age 22, grade 78
  David: age 20, grade 92
  Eve: age 18, grade 88

年齢でソート:
  Eve: age 18, grade 88
  Bob: age 19, grade 90
  David: age 20, grade 92
  Alice: age 21, grade 85
  Charlie: age 22, grade 78

成績でソート (最高から最低へ):
  David: age 20, grade 92
  Bob: age 19, grade 90
  Eve: age 18, grade 88
  Alice: age 21, grade 85
  Charlie: age 22, grade 78

次のステップでは、lambda 関数を使用した、より高度なソートテクニックを探求します。

高度なソートテクニック

基本を理解したので、lambda 関数を使用した、より高度なソートテクニックを探求しましょう。

辞書のソート

辞書は Python で一般的なデータ構造であり、辞書のリストをソートする必要があることがよくあります。sorting_dictionaries.py というファイルを作成します。

## 辞書のリストのソート
products = [
    {"name": "Laptop", "price": 999.99, "stock": 25},
    {"name": "Phone", "price": 499.50, "stock": 42},
    {"name": "Tablet", "price": 299.75, "stock": 15},
    {"name": "Headphones", "price": 149.99, "stock": 34},
    {"name": "Mouse", "price": 24.99, "stock": 55}
]

## 元の製品を出力
print("元の製品リスト:")
for product in products:
    print(f"  {product['name']}: ${product['price']}, 在庫:{product['stock']}")

## 価格でソート (最低から最高へ)
by_price = sorted(products, key=lambda product: product["price"])
print("\n価格でソート (最低から最高へ):")
for product in by_price:
    print(f"  {product['name']}: ${product['price']}, 在庫:{product['stock']}")

## 在庫でソート (最高から最低へ)
by_stock = sorted(products, key=lambda product: product["stock"], reverse=True)
print("\n在庫でソート (最高から最低へ):")
for product in by_stock:
    print(f"  {product['name']}: ${product['price']}, 在庫:{product['stock']}")

## 名前でソート (アルファベット順)
by_name = sorted(products, key=lambda product: product["name"])
print("\n名前でソート:")
for product in by_name:
    print(f"  {product['name']}: ${product['price']}, 在庫:{product['stock']}")

このファイルを実行します。

python3 sorting_dictionaries.py

製品がさまざまな方法でソートされているのがわかるはずです。

元の製品リスト:
  Laptop: $999.99, 在庫: 25
  Phone: $499.5, 在庫: 42
  Tablet: $299.75, 在庫: 15
  Headphones: $149.99, 在庫: 34
  Mouse: $24.99, 在庫: 55

価格でソート (最低から最高へ):
  Mouse: $24.99, 在庫: 55
  Headphones: $149.99, 在庫: 34
  Tablet: $299.75, 在庫: 15
  Phone: $499.5, 在庫: 42
  Laptop: $999.99, 在庫: 25

在庫でソート (最高から最低へ):
  Mouse: $24.99, 在庫: 55
  Phone: $499.5, 在庫: 42
  Headphones: $149.99, 在庫: 34
  Laptop: $999.99, 在庫: 25
  Tablet: $299.75, 在庫: 15

名前でソート:
  Headphones: $149.99, 在庫: 34
  Laptop: $999.99, 在庫: 25
  Mouse: $24.99, 在庫: 55
  Phone: $499.5, 在庫: 42
  Tablet: $299.75, 在庫: 15

マルチレベルソート

場合によっては、複数の基準を使用して項目をソートする必要があります。たとえば、学生を最初に成績でソートし、同じ成績の学生を年齢でソートしたい場合があります。

multi_level_sorting.py というファイルを作成します。

## マルチレベルソートの例
students = [
    {"name": "Alice", "grade": "A", "age": 21},
    {"name": "Bob", "grade": "B", "age": 19},
    {"name": "Charlie", "grade": "A", "age": 22},
    {"name": "David", "grade": "C", "age": 20},
    {"name": "Eve", "grade": "B", "age": 18},
    {"name": "Frank", "grade": "A", "age": 19}
]

print("元の学生リスト:")
for student in students:
    print(f"  {student['name']}: 成績 {student['grade']}, 年齢 {student['age']}")

## 成績でソート (A から C)、次に年齢でソート (若い順から古い順)
## 成績でソートするために、成績の優先順位の辞書を作成します
grade_priority = {"A": 1, "B": 2, "C": 3}  ## A が最高の優先順位 (最も低い数値)

by_grade_then_age = sorted(students,
                           key=lambda student: (grade_priority[student["grade"]], student["age"]))

print("\n成績でソート (A が最初)、次に年齢でソート (若い順):")
for student in by_grade_then_age:
    print(f"  {student['name']}: 成績 {student['grade']}, 年齢 {student['age']}")

## 年齢でソート (古い順から若い順)、次に名前でソート (アルファベット順)
by_age_then_name = sorted(students,
                          key=lambda student: (-student["age"], student["name"]))

print("\n年齢でソート (古い順)、次に名前でソート:")
for student in by_age_then_name:
    print(f"  {student['name']}: 成績 {student['grade']}, 年齢 {student['age']}")

このファイルを実行します。

python3 multi_level_sorting.py

次のように表示されるはずです。

元の学生リスト:
  Alice: 成績 A, 年齢 21
  Bob: 成績 B, 年齢 19
  Charlie: 成績 A, 年齢 22
  David: 成績 C, 年齢 20
  Eve: 成績 B, 年齢 18
  Frank: 成績 A, 年齢 19

成績でソート (A が最初)、次に年齢でソート (若い順):
  Frank: 成績 A, 年齢 19
  Alice: 成績 A, 年齢 21
  Charlie: 成績 A, 年齢 22
  Eve: 成績 B, 年齢 18
  Bob: 成績 B, 年齢 19
  David: 成績 C, 年齢 20

年齢でソート (古い順)、次に名前でソート:
  Charlie: 成績 A, 年齢 22
  Alice: 成績 A, 年齢 21
  David: 成績 C, 年齢 20
  Bob: 成績 B, 年齢 19
  Frank: 成績 A, 年齢 19
  Eve: 成績 B, 年齢 18

lambda 関数内でタプルを使用して、複数のソート基準を定義したことに注目してください。タプルの最初の要素は主要なソートキーであり、後続の要素はタイブレークに使用されます。

負の符号 -student["age"] を使用して、年齢を降順にソートしました。このテクニックは、数値を逆順にソートする場合に役立ちます。

カスタムオブジェクトのソート

カスタムクラスオブジェクトをソートする方法を示す最後の例を作成しましょう。sorting_objects.py というファイルを作成します。

## カスタムクラスのオブジェクトのソート
class Person:
    def __init__(self, name, age, height):
        self.name = name
        self.age = age
        self.height = height  ## cm 単位

    def __repr__(self):
        return f"Person(name='{self.name}', age={self.age}, height={self.height}cm)"

## Person オブジェクトのリストを作成する
people = [
    Person("Alice", 25, 165),
    Person("Bob", 30, 180),
    Person("Charlie", 22, 175),
    Person("David", 35, 170),
    Person("Eve", 28, 160)
]

print("元の人のリスト:")
for person in people:
    print(f"  {person}")

## 年齢でソート
by_age = sorted(people, key=lambda person: person.age)
print("\n年齢でソート:")
for person in by_age:
    print(f"  {person}")

## 身長でソート
by_height = sorted(people, key=lambda person: person.height)
print("\n身長でソート:")
for person in by_height:
    print(f"  {person}")

## 名前の長さでソートし、次に年齢でソート
by_name_length_then_age = sorted(people, key=lambda person: (len(person.name), person.age))
print("\n名前の長さでソートし、次に年齢でソート:")
for person in by_name_length_then_age:
    print(f"  {person}")

このファイルを実行します。

python3 sorting_objects.py

次のように表示されるはずです。

元の人のリスト:
  Person(name='Alice', age=25, height=165cm)
  Person(name='Bob', age=30, height=180cm)
  Person(name='Charlie', age=22, height=175cm)
  Person(name='David', age=35, height=170cm)
  Person(name='Eve', age=28, height=160cm)

年齢でソート:
  Person(name='Charlie', age=22, height=175cm)
  Person(name='Alice', age=25, height=165cm)
  Person(name='Eve', age=28, height=160cm)
  Person(name='Bob', age=30, height=180cm)
  Person(name='David', age=35, height=170cm)

身長でソート:
  Person(name='Eve', age=28, height=160cm)
  Person(name='Alice', age=25, height=165cm)
  Person(name='David', age=35, height=170cm)
  Person(name='Charlie', age=22, height=175cm)
  Person(name='Bob', age=30, height=180cm)

名前の長さでソートし、次に年齢でソート:
  Person(name='Bob', age=30, height=180cm)
  Person(name='Eve', age=28, height=160cm)
  Person(name='Alice', age=25, height=165cm)
  Person(name='David', age=35, height=170cm)
  Person(name='Charlie', age=22, height=175cm)

この例は、lambda 関数を使用して、カスタムオブジェクトの属性に直接アクセスしてソートする方法を示しています。

実世界のソートアプリケーション

これまでに学んだことを、より現実的なデータ分析シナリオに適用してみましょう。書籍のデータセットを分析し、さまざまな基準でソートできるプログラムを作成します。

book_analyzer.py というファイルを作成します。

## 書籍データ分析アプリケーション
books = [
    {
        "title": "The Great Gatsby",
        "author": "F. Scott Fitzgerald",
        "year": 1925,
        "pages": 180,
        "rating": 4.2,
        "genres": ["Classic", "Fiction"]
    },
    {
        "title": "To Kill a Mockingbird",
        "author": "Harper Lee",
        "year": 1960,
        "pages": 281,
        "rating": 4.3,
        "genres": ["Classic", "Fiction", "Drama"]
    },
    {
        "title": "1984",
        "author": "George Orwell",
        "year": 1949,
        "pages": 328,
        "rating": 4.2,
        "genres": ["Dystopian", "Fiction", "Political"]
    },
    {
        "title": "The Hobbit",
        "author": "J.R.R. Tolkien",
        "year": 1937,
        "pages": 310,
        "rating": 4.4,
        "genres": ["Fantasy", "Adventure"]
    },
    {
        "title": "Harry Potter and the Sorcerer's Stone",
        "author": "J.K. Rowling",
        "year": 1997,
        "pages": 309,
        "rating": 4.5,
        "genres": ["Fantasy", "Adventure", "Young Adult"]
    },
    {
        "title": "The Catcher in the Rye",
        "author": "J.D. Salinger",
        "year": 1951,
        "pages": 214,
        "rating": 3.8,
        "genres": ["Fiction", "Coming of Age"]
    }
]

def print_books(book_list, heading):
    """書籍をフォーマットされた方法で出力するためのヘルパー関数"""
    print(f"\n{heading}")
    print("-" * 80)
    for book in book_list:
        genres = ", ".join(book["genres"])
        print(f"{book['title']} by {book['author']} ({book['year']}) - {book['pages']} pages")
        print(f"  Rating: {book['rating']}, Genres: {genres}")
    print("-" * 80)

## 元のリストを出力
print_books(books, "元の書籍リスト")

## さまざまな基準で書籍をソート
sort_options = {
    "1": ("タイトル (A-Z)", lambda b: b["title"]),
    "2": ("著者 (A-Z)", lambda b: b["author"]),
    "3": ("出版年 (古い順)", lambda b: b["year"]),
    "4": ("出版年 (新しい順)", lambda b: -b["year"]),
    "5": ("評価 (高い順)", lambda b: -b["rating"]),
    "6": ("ページ数 (少ない順)", lambda b: b["pages"]),
    "7": ("ジャンル数", lambda b: len(b["genres"])),
}

## ソートオプションを表示
print("\nソートオプション:")
for key, (description, _) in sort_options.items():
    print(f"{key}. {description}")

## このチュートリアルのすべてのソート例を自動的に表示
for option, (description, sort_key) in sort_options.items():
    sorted_books = sorted(books, key=sort_key)
    print_books(sorted_books, f"書籍を {description} でソート")

このファイルを実行します。

python3 book_analyzer.py

書籍が複数の方法でソートされているのがわかります。

元の書籍リスト
--------------------------------------------------------------------------------
The Great Gatsby by F. Scott Fitzgerald (1925) - 180 pages
  Rating: 4.2, Genres: Classic, Fiction
To Kill a Mockingbird by Harper Lee (1960) - 281 pages
  Rating: 4.3, Genres: Classic, Fiction, Drama
1984 by George Orwell (1949) - 328 pages
  Rating: 4.2, Genres: Dystopian, Fiction, Political
The Hobbit by J.R.R. Tolkien (1937) - 310 pages
  Rating: 4.4, Genres: Fantasy, Adventure
Harry Potter and the Sorcerer's Stone by J.K. Rowling (1997) - 309 pages
  Rating: 4.5, Genres: Fantasy, Adventure, Young Adult
The Catcher in the Rye by J.D. Salinger (1951) - 214 pages
  Rating: 3.8, Genres: Fiction, Coming of Age
--------------------------------------------------------------------------------

ソートオプション:
1. タイトル (A-Z)
2. 著者 (A-Z)
3. 出版年 (古い順)
4. 出版年 (新しい順)
5. 評価 (高い順)
6. ページ数 (少ない順)
7. ジャンル数

書籍を タイトル (A-Z) でソート
...

[出力は、すべての異なるソート例で続きます]

この例は、lambda 関数を実際のアプリケーションで使用して、柔軟なソート機能を提供する方法を示しています。lambda 関数とその説明を辞書に格納したことに注目してください。これにより、実際のアプリケーションでより多くのソートオプションを簡単に追加できます。

ユーザーがソートオプションを選択できるインタラクティブバージョンを作成しましょう。interactive_book_sorter.py というファイルを作成します。

## インタラクティブな書籍ソーターアプリケーション
books = [
    {
        "title": "The Great Gatsby",
        "author": "F. Scott Fitzgerald",
        "year": 1925,
        "pages": 180,
        "rating": 4.2,
        "genres": ["Classic", "Fiction"]
    },
    {
        "title": "To Kill a Mockingbird",
        "author": "Harper Lee",
        "year": 1960,
        "pages": 281,
        "rating": 4.3,
        "genres": ["Classic", "Fiction", "Drama"]
    },
    {
        "title": "1984",
        "author": "George Orwell",
        "year": 1949,
        "pages": 328,
        "rating": 4.2,
        "genres": ["Dystopian", "Fiction", "Political"]
    },
    {
        "title": "The Hobbit",
        "author": "J.R.R. Tolkien",
        "year": 1937,
        "pages": 310,
        "rating": 4.4,
        "genres": ["Fantasy", "Adventure"]
    },
    {
        "title": "Harry Potter and the Sorcerer's Stone",
        "author": "J.K. Rowling",
        "year": 1997,
        "pages": 309,
        "rating": 4.5,
        "genres": ["Fantasy", "Adventure", "Young Adult"]
    },
    {
        "title": "The Catcher in the Rye",
        "author": "J.D. Salinger",
        "year": 1951,
        "pages": 214,
        "rating": 3.8,
        "genres": ["Fiction", "Coming of Age"]
    }
]

def print_books(book_list, heading):
    """書籍をフォーマットされた方法で出力するためのヘルパー関数"""
    print(f"\n{heading}")
    print("-" * 80)
    for book in book_list:
        genres = ", ".join(book["genres"])
        print(f"{book['title']} by {book['author']} ({book['year']}) - {book['pages']} pages")
        print(f"  Rating: {book['rating']}, Genres: {genres}")
    print("-" * 80)

## ソートオプションを定義する
sort_options = {
    "1": ("タイトル (A-Z)", lambda b: b["title"]),
    "2": ("著者 (A-Z)", lambda b: b["author"]),
    "3": ("出版年 (古い順)", lambda b: b["year"]),
    "4": ("出版年 (新しい順)", lambda b: -b["year"]),
    "5": ("評価 (高い順)", lambda b: -b["rating"]),
    "6": ("ページ数 (少ない順)", lambda b: b["pages"]),
    "7": ("ジャンル数", lambda b: len(b["genres"])),
}

## 元のリストを出力
print_books(books, "書籍カタログ")

while True:
    ## ソートオプションを表示
    print("\n書籍をどのようにソートしますか?")
    for key, (description, _) in sort_options.items():
        print(f"{key}. {description}")
    print("0. 終了")

    choice = input("\n選択肢を入力してください (0-7): ")

    if choice == "0":
        print("書籍ソーターをご利用いただきありがとうございます。さようなら!")
        break
    elif choice in sort_options:
        description, sort_key = sort_options[choice]
        sorted_books = sorted(books, key=sort_key)
        print_books(sorted_books, f"書籍を {description} でソート")
    else:
        print("無効な選択です。もう一度お試しください。")

このインタラクティブバージョンを実行します。

python3 interactive_book_sorter.py

これにより、さまざまなソートオプションを選択して、結果を確認できます。終了したら、「0」を入力してプログラムを終了します。

このインタラクティブアプリケーションは、lambda 関数が、実際のアプリケーションでさまざまなソートオプションを簡単に実装できることを示しています。各ソートオプションは、書籍辞書から関連情報を抽出する lambda 関数にすぎません。

まとめ

Python でのカスタムソートに lambda 関数を使用するこのチュートリアルを修了したことをおめでとうございます。以下のことを学びました。

  1. lambda 関数の基本と、通常の関数との違い
  2. Python のソート関数 (sorted() および .sort()) で lambda 関数を使用する方法
  3. さまざまなデータ構造をソートするためのテクニック:
    • 単純な値のリスト
    • タプルのリスト
    • 辞書のリスト
    • カスタムオブジェクト
  4. lambda 関数でタプルを使用したマルチレベルソート
  5. 実際のデータ分析アプリケーションで lambda 関数を適用する方法

これらのスキルは、今後の Python プロジェクトにおけるデータ処理、分析、操作に非常に役立ちます。Lambda 関数は、ソート動作をカスタマイズするための簡潔で強力な方法を提供し、コードをより表現力豊かにし、保守を容易にします。

Python の学習を続ける中で、lambda 関数はソートだけでなく、map()filter()reduce() などの他の高階関数にも役立つことがわかるでしょう。このチュートリアルで学んだテクニックは、これらのより高度なアプリケーションの強固な基盤となります。