0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Gemini に Go 言語で Java の ArrayListを作らせてみた (第五回 Sort もしたい)

Last updated at Posted at 2025-08-08

なぜ Go 言語にコレクションクラスがないんだ!そうだ。 AI に作らせよう。

という訳で、Gemini だけで ArrayListGo で作らせてみました。

そのときの内容を6回に分けてお伝えしていこうと思います。

第五回 Sort もしたい

分割して掲載する都合上、実際に質問を投げた順番と掲載の順番とを少々入れ替えてあります。

Geminiからは、毎回コード全体が出力されましたが、
記事が長くなりすぎてしまうため、変更があった部分だけをお送りいたします。

並べ替えを可能にするには制約 cmp.Orderd を満たしている必要があり、
今回はもうひとつその構造体を追加してもらいます。

MyOrderedArrayList 構造体

質問

新たに MyComparableArrayList を埋め込んだ構造体MyOrderedArrayListを作ってください
Tの制約は cmp.Orderd です

おっと。Orderedタイポした。

回答

承知いたしました。MyComparableArrayListを埋め込み、さらに要素の制約をcmp.Ordered(順序付け可能)にすることで、並べ替えなどの操作が可能な新しいリスト型、MyOrderedArrayList を作成します。

これにより、MyOrderedArrayListは以下のような特徴を持ちます。

  • MyArrayListMyComparableArrayListのすべてのメソッドを継承します。
  • 要素がint, float64, stringなどの順序付け可能な型に限定されます。
  • 将来的にソートなどの順序に関連するメソッドを追加できるようになります。

MyOrderedArrayList の実装

以下に、MyOrderedArrayList構造体の定義と、その初期化関数、および使用例を示します。

package main

import (
	"cmp" // cmp.Ordered 制約のためにインポート
	"fmt"
)

// MyArrayList は基本的な動的配列機能を提供します。
// 任意の型の要素を格納できます。
type MyArrayList[T any] struct {
	elements []T
}

// MyComparableArrayList は比較可能な要素に特化した動的配列です。
// MyArrayListを埋め込むことで、そのメソッドを継承します。
type MyComparableArrayList[T comparable] struct {
	MyArrayList[T] // MyArrayListを埋め込む
}

// MyOrderedArrayList は順序付け可能な要素に特化した動的配列です。
// MyComparableArrayListを埋め込むことで、そのメソッドを継承します。
// T は cmp.Ordered (比較演算子 <, <=, ==, !=, >=, > が使える型) の制約を受けます。
type MyOrderedArrayList[T cmp.Ordered] struct {
	MyComparableArrayList[T] // MyComparableArrayListを埋め込む
}

// NewMyOrderedArrayList は新しいMyOrderedArrayListを初期化して返します。
func NewMyOrderedArrayList[T cmp.Ordered]() *MyOrderedArrayList[T] {
	return &MyOrderedArrayList[T]{
		MyComparableArrayList: *NewMyComparableArrayList[T](), // 埋め込んだMyComparableArrayListを初期化
	}
}

func main() {
	fmt.Println("--- MyOrderedArrayList の使用例 ---")
	intList := NewMyOrderedArrayList[int]()
	intList.Add(50)
	intList.Add(20)
	intList.Add(80)
	intList.Add(30)
	fmt.Println("Original IntList:", intList) // Original IntList: [50 20 80 30]

	// MyArrayList と MyComparableArrayList から継承したメソッドの使用
	fmt.Println("\n--- 継承メソッドのテスト ---")
	fmt.Println("Size:", intList.Size())              // Size: 4
	fmt.Println("Contains 20?", intList.Contains(20)) // Contains 20? true
	fmt.Println("Remove 80?", intList.Remove(80))     // Remove 80? true
	fmt.Println("List after Remove 80:", intList)     // List after Remove 80: [50 20 30]

	otherNums := []int{10, 30, 60}
	fmt.Printf("Contains all %v? %t\n", otherNums, intList.ContainsAll(otherNums)) // Contains all [10 30 60]? false (10, 60がない)

	intList.AddAll([]int{10, 60})
	fmt.Println("List after AddAll:", intList) // List after AddAll: [50 20 30 10 60]

	// RemoveIf も使用可能 (MyArrayListから継承)
	removedSmall := intList.RemoveIf(func(e int) bool {
		return e < 30
	})
	fmt.Println("Removed numbers < 30?", removedSmall) // Removed numbers < 30? true
	fmt.Println("List after RemoveIf (<30):", intList) // List after RemoveIf (<30): [50 30 60]

	// RetainAll も使用可能 (MyComparableArrayListから継承)
	toRetain := []int{50, 30, 90}
	retained := intList.RetainAll(toRetain)
	fmt.Printf("Retained %v in list: %t\n", toRetain, retained) // Retained [50 30 90] in list: true
	fmt.Println("List after RetainAll:", intList)               // List after RetainAll: [50 30]

	// Equals も使用可能 (MyComparableArrayListから継承)
	anotherList := NewMyOrderedArrayList[int]()
	anotherList.AddAll([]int{50, 30})
	fmt.Println("Another List:", anotherList)
	fmt.Printf("IntList equals Another List? %t\n", intList.Equals(anotherList)) // IntList equals Another List? true

	// ReplaceAll も使用可能 (MyArrayListから継承)
	intList.ReplaceAll(func(e int) int {
		return e * 10
	})
	fmt.Println("List after ReplaceAll (*10):", intList) // List after ReplaceAll (*10): [500 300]

	fmt.Println("\n--- String型のMyOrderedArrayList ---")
	stringList := NewMyOrderedArrayList[string]()
	stringList.AddAll([]string{"zebra", "apple", "cat", "dog"})
	fmt.Println("Original StringList:", stringList) // Original StringList: [zebra apple cat dog]

	// 例えば、ソートメソッドをここに追加できる
	// sort.Slice(stringList.elements, func(i, j int) bool {
	// 	return stringList.elements[i] < stringList.elements[j]
	// })
	// fmt.Println("Sorted StringList:", stringList) // Sorted StringList: [apple cat dog zebra]
}

MyOrderedArrayListの解説

  • type MyOrderedArrayList[T cmp.Ordered] struct { ... }:
    • ジェネリクス型パラメータTに cmp.Ordered という制約が適用されています。
    • cmp.OrderedはGo 1.21で導入されたプリデクレア型(predeclared type)で、比較演算子(<, <=, ==, !=, >=, >)が定義されているすべての型(整数型、浮動小数点型、文字列型など)を表します。これにより、これらの型を安全に順序付けて比較できます。
    • MyComparableArrayList[T]を埋め込み: MyOrderedArrayListMyComparableArrayList[T]をフィールドとして埋め込んでいます。これにより、MyArrayListMyComparableArrayListのすべてのメソッドが自動的にMyOrderedArrayListでも利用可能になります。これはGoにおける「コンポジションによる継承」の強力な例です。
  • NewMyOrderedArrayList関数:
    • MyOrderedArrayListのインスタンスを初期化するためのコンストラクタ関数です。
    • 内部で埋め込んだMyComparableArrayListも適切にNewMyComparableArrayList[T]()を呼び出して初期化しています。

利用例とメリット

  • 継承されたメソッド: Add, Get, RemoveAt, Contains, Equals, RemoveIf, ReplaceAll, RetainAllなど、これまでのすべてのメソッドがMyOrderedArrayListのインスタンスでそのまま利用できます。
  • 型安全性: MyOrderedArrayList[T]を作成する際に、Tcmp.Orderedではない型(例: struct[]byte)を指定しようとすると、コンパイルエラーになります。これにより、順序付けが必要な操作に対して安全な型保証が提供されます。
  • 将来の拡張性: cmp.Ordered制約があるため、Sort()Min(), Max()などの、要素の順序に依存するメソッドをMyOrderedArrayListに容易に追加できるようになります。

これで、Goの型システムとジェネリクスを段階的に活用し、より特定の用途に特化したリスト構造を構築できました。

感想

タイポしたのに何も言わずに修正してくれた。
やさしい。

Sort メソッド

質問

MyOrderedArrayList を作成したときの解説でも言われていたSortメソッドを追加してみます。

sortを追加してください

回答

承知いたしました。MyOrderedArrayListに、要素をソートするSort()メソッドを追加します。

Sort()メソッドは要素の順序に依存するため、cmp.Ordered制約を持つ MyOrderedArrayList に実装するのが適切です。Goの標準ライブラリのslices.Sort(Go 1.21以降)を利用することで、効率的かつ簡潔にソート機能を実装できます。

MyOrderedArrayListSort()メソッドを追加

以下に、Sort()メソッドを追加したMyOrderedArrayListの完全なコードを示します。

package main

import (
	"cmp"
	"fmt"
	"slices" // slices.Sortのためにインポート (Go 1.21+)
)

// MyArrayList は基本的な動的配列機能を提供します。
// 任意の型の要素を格納できます。
type MyArrayList[T any] struct {
	elements []T
}

// MyComparableArrayList は比較可能な要素に特化した動的配列です。
// MyArrayListを埋め込むことで、そのメソッドを継承します。
type MyComparableArrayList[T comparable] struct {
	MyArrayList[T] // MyArrayListを埋め込む
}

// MyOrderedArrayList は順序付け可能な要素に特化した動的配列です。
// MyComparableArrayListを埋め込むことで、そのメソッドを継承します。
// T は cmp.Ordered (比較演算子 <, <=, ==, !=, >=, > が使える型) の制約を受けます。
type MyOrderedArrayList[T cmp.Ordered] struct {
	MyComparableArrayList[T] // MyComparableArrayListを埋め込む
}

// Sort はリストの要素を自然順序でソートします。
func (list *MyOrderedArrayList[T]) Sort() {
	slices.Sort(list.elements)
}

func main() {
	fmt.Println("--- MyOrderedArrayList の使用例 ---")
	intList := NewMyOrderedArrayList[int]()
	intList.Add(50)
	intList.Add(20)
	intList.Add(80)
	intList.Add(30)
	fmt.Println("Original IntList:", intList) // Original IntList: [50 20 80 30]

	fmt.Println("\n--- Sort() のテスト (int) ---")
	intList.Sort()
	fmt.Println("Sorted IntList:", intList) // Sorted IntList: [20 30 50 80]

	stringList := NewMyOrderedArrayList[string]()
	stringList.AddAll([]string{"zebra", "apple", "cat", "dog", "Banana"}) // 'B'anana と 'a'pple の順序もテスト
	fmt.Println("\nOriginal StringList:", stringList)                     // Original StringList: [zebra apple cat dog Banana]

	fmt.Println("\n--- Sort() のテスト (string) ---")
	stringList.Sort()
	// Goのデフォルトの文字列比較はASCII/UTF-8順なので、大文字が小文字より前に来る
	fmt.Println("Sorted StringList:", stringList) // Sorted StringList: [Banana apple cat dog zebra]

	floatList := NewMyOrderedArrayList[float64]()
	floatList.AddAll([]float64{3.14, 1.618, 2.718, 0.577})
	fmt.Println("\nOriginal FloatList:", floatList) // Original FloatList: [3.14 1.618 2.718 0.577]

	fmt.Println("\n--- Sort() のテスト (float64) ---")
	floatList.Sort()
	fmt.Println("Sorted FloatList:", floatList) // Sorted FloatList: [0.577 1.618 2.718 3.14]

	// 継承されたEqualsメソッドのlices.Equalへの変更をテスト
	list1 := NewMyComparableArrayList[int]()
	list1.AddAll([]int{1, 2, 3})
	list2 := NewMyComparableArrayList[int]()
	list2.AddAll([]int{1, 2, 3})
	fmt.Printf("\nList1 equals List2? %t (using slices.Equal)\n", list1.Equals(list2)) // true
}

Sort() メソッドの解説

  • func (list *MyOrderedArrayList[T]) Sort():
    • このメソッドは引数を取らず、リストの要素を インプレース(in-place) でソートします。つまり、既存のリストの順序が変更されます。
    • slices.Sort(list.elements):

Sort()メソッドの配置

Sort()メソッドは要素の順序に直接アクセスして並べ替えを行うため、cmp.Ordered制約を持つ MyOrderedArrayList に実装するのが最も適切です。

その他の更新

MyComparableArrayListEquals()メソッドの内部実装を、より簡潔でGoの標準ライブラリに沿ったslices.Equalを使用するように変更しました](https://www.google.com/search?q=https://pkg.go.dev/slices%23Equal)%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E5%A4%89%E6%9B%B4%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F)。これにより、`MyComparableArrayListのEquals`は、長さが同じで要素が同じ順序で現れる場合に`true`を返すという定義により厳密に合致するようになりました。

これで、順序付け可能な要素を持つリストに対してソート機能が追加されました。

感想

お、リンク張ってくれたマークダウンがずれてる。

まとめ

ここまできたら、MyOrderedArrayList を作成したときの解説にも合った通り、Min, Maxなども追加していくこともできるでしょう。

次回で最終回、いままでの振り返りになります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?