課題4: データ構造の実装
課題概要
スライスとマップを使って、学生管理システムとテキスト分析ツールを実装します。データ構造の特性を理解し、効率的なコードを書く練習をします。
マンダトリー要件
要件1: 学生管理システム
学生データを管理するシステムを実装してください。
ファイル: student/student.go
package student
type Student struct {
ID int
Name string
Grade int
Score float64
}
type StudentManager struct {
students []Student
byID map[int]*Student
}
// NewStudentManager は新しいマネージャーを作成
func NewStudentManager() *StudentManager {
return &StudentManager{
students: make([]Student, 0, 100),
byID: make(map[int]*Student),
}
}
// Add は学生を追加
func (sm *StudentManager) Add(s Student) error {
// TODO: 実装してください
// - IDが既に存在する場合はエラー
// - studentsスライスとbyIDマップの両方に追加
}
// GetByID はIDで学生を検索
func (sm *StudentManager) GetByID(id int) (*Student, bool) {
// TODO: 実装してください
}
// GetByGrade は学年で学生をフィルタリング
func (sm *StudentManager) GetByGrade(grade int) []Student {
// TODO: 実装してください
}
// GetTopN はスコアの上位N人を返す
func (sm *StudentManager) GetTopN(n int) []Student {
// TODO: 実装してください
// ヒント: sort.Slice を使用
}
// AverageScore は平均スコアを計算
func (sm *StudentManager) AverageScore() float64 {
// TODO: 実装してください
}
// Count は学生数を返す
func (sm *StudentManager) Count() int {
return len(sm.students)
}
要件2: テキスト分析ツール
テキストを分析するツールを実装してください。
ファイル: textanalysis/analysis.go
package textanalysis
import (
"strings"
"unicode"
)
type TextStats struct {
CharCount int
WordCount int
LineCount int
WordFreq map[string]int
TopWords []WordFrequency
}
type WordFrequency struct {
Word string
Count int
}
// Analyze はテキストを分析して統計を返す
func Analyze(text string) TextStats {
// TODO: 実装してください
// 1. 文字数を数える(空白を除く)
// 2. 単語数を数える
// 3. 行数を数える
// 4. 各単語の出現回数をカウント
// 5. 上位10個の単語を抽出
}
// normalizeWord は単語を正規化(小文字化、記号削除)
func normalizeWord(word string) string {
// TODO: 実装してください
}
// CountUniqueWords はユニークな単語数を返す
func CountUniqueWords(text string) int {
// TODO: 実装してください
}
// FindLongestWord は最長の単語を返す
func FindLongestWord(text string) string {
// TODO: 実装してください
}
要件3: スライス操作ユーティリティ
汎用的なスライス操作関数を実装してください。
ファイル: sliceutil/sliceutil.go
package sliceutil
// Reverse はスライスを反転(in-place)
func Reverse(s []int) {
// TODO: 実装してください
}
// Filter は条件を満たす要素のみを抽出
func Filter(s []int, predicate func(int) bool) []int {
// TODO: 実装してください
}
// Map は各要素に関数を適用
func Map(s []int, fn func(int) int) []int {
// TODO: 実装してください
}
// Reduce はスライスを単一の値に集約
func Reduce(s []int, initial int, fn func(acc, val int) int) int {
// TODO: 実装してください
}
// RemoveDuplicates は重複を削除
func RemoveDuplicates(s []int) []int {
// TODO: 実装してください
// ヒント: map を使う
}
// Chunk はスライスを指定サイズに分割
func Chunk(s []int, size int) [][]int {
// TODO: 実装してください
}
要件4: メインプログラム
すべての機能をテストするプログラムを作成してください。
ファイル: main.go
package main
import (
"fmt"
"yourproject/student"
"yourproject/textanalysis"
"yourproject/sliceutil"
)
func main() {
// 学生管理システムのテスト
testStudentManager()
// テキスト分析のテスト
testTextAnalysis()
// スライスユーティリティのテスト
testSliceUtil()
}
func testStudentManager() {
fmt.Println("=== Student Manager ===")
sm := student.NewStudentManager()
students := []student.Student{
{ID: 1, Name: "Alice", Grade: 3, Score: 85.5},
{ID: 2, Name: "Bob", Grade: 2, Score: 92.0},
{ID: 3, Name: "Carol", Grade: 3, Score: 78.5},
{ID: 4, Name: "David", Grade: 2, Score: 88.0},
{ID: 5, Name: "Eve", Grade: 3, Score: 95.5},
}
for _, s := range students {
sm.Add(s)
}
fmt.Printf("Total students: %d\n", sm.Count())
fmt.Printf("Average score: %.2f\n", sm.AverageScore())
top3 := sm.GetTopN(3)
fmt.Println("Top 3 students:")
for _, s := range top3 {
fmt.Printf(" %s: %.1f\n", s.Name, s.Score)
}
}
func testTextAnalysis() {
fmt.Println("\n=== Text Analysis ===")
text := `Go is a statically typed, compiled programming language.
Go is designed for building simple, reliable, and efficient software.
Go was created at Google.`
stats := textanalysis.Analyze(text)
fmt.Printf("Characters: %d\n", stats.CharCount)
fmt.Printf("Words: %d\n", stats.WordCount)
fmt.Printf("Lines: %d\n", stats.LineCount)
fmt.Printf("Unique words: %d\n", len(stats.WordFreq))
fmt.Println("Top 5 words:")
for i, wf := range stats.TopWords {
if i >= 5 {
break
}
fmt.Printf(" %s: %d\n", wf.Word, wf.Count)
}
}
func testSliceUtil() {
fmt.Println("\n=== Slice Utilities ===")
numbers := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
// Filter: 偶数のみ
even := sliceutil.Filter(numbers, func(n int) bool { return n%2 == 0 })
fmt.Println("Even numbers:", even)
// Map: 各要素を2倍
doubled := sliceutil.Map(numbers, func(n int) int { return n * 2 })
fmt.Println("Doubled:", doubled)
// Reduce: 合計を計算
sum := sliceutil.Reduce(numbers, 0, func(acc, val int) int { return acc + val })
fmt.Println("Sum:", sum)
}
期待される出力
=== Student Manager ===
Total students: 5
Average score: 87.90
Top 3 students:
Eve: 95.5
Bob: 92.0
David: 88.0
=== Text Analysis ===
Characters: 142
Words: 23
Lines: 3
Unique words: 19
Top 5 words:
go: 3
is: 2
a: 1
statically: 1
typed: 1
=== Slice Utilities ===
Even numbers: [2 4 6 8 10]
Doubled: [2 4 6 8 10 12 14 16 18 20]
Sum: 55
ボーナス課題
ボーナス1: 高度な学生管理機能
学生管理システムに追加機能を実装してください。
// Delete は学生を削除
func (sm *StudentManager) Delete(id int) error {
// TODO: スライスとマップの両方から削除
}
// Update は学生情報を更新
func (sm *StudentManager) Update(id int, s Student) error {
// TODO: 既存の学生情報を更新
}
// GetStatsByGrade は学年ごとの統計を返す
func (sm *StudentManager) GetStatsByGrade() map[int]GradeStats {
// TODO: 各学年の人数、平均点、最高点、最低点を計算
}
type GradeStats struct {
Count int
Average float64
Max float64
Min float64
}
ボーナス2: LRUキャッシュの実装
最近使用された要素を保持するLRUキャッシュを実装してください。
package cache
type LRUCache struct {
capacity int
cache map[int]int
order []int // 使用順序を記録
}
func NewLRUCache(capacity int) *LRUCache {
// TODO: 実装してください
}
func (c *LRUCache) Get(key int) (int, bool) {
// TODO: 取得と同時に使用順序を更新
}
func (c *LRUCache) Put(key, value int) {
// TODO: 容量を超えたら最も古い要素を削除
}
ボーナス3: マップのマージとディープコピー
マップを操作するユーティリティ関数を実装してください。
package maputil
// Merge は複数のマップをマージ
func Merge(maps ...map[string]int) map[string]int {
// TODO: 実装してください
// 同じキーがある場合は後のマップの値を優先
}
// DeepCopy はマップの深いコピーを作成
func DeepCopy(m map[string]int) map[string]int {
// TODO: 実装してください
}
// Keys はマップのキーをスライスで返す
func Keys(m map[string]int) []string {
// TODO: 実装してください
}
// Values はマップの値をスライスで返す
func Values(m map[string]int) []int {
// TODO: 実装してください
}
// Invert はキーと値を入れ替える
func Invert(m map[string]int) map[int]string {
// TODO: 実装してください
// 注意: 値の重複がある場合は上書きされる
}
評価基準
| 項目 | 配点 | 詳細 |
|---|---|---|
| 学生管理システム | 30点 | CRUD操作、検索、集計が正しく動作 |
| テキスト分析 | 25点 | 文字/単語/行のカウント、頻度分析が正確 |
| スライスユーティリティ | 20点 | 各関数が正しく実装されている |
| メインプログラム | 25点 | すべての機能が統合され動作する |
| **ボーナス1** | 10点 | 高度な学生管理機能が実装されている |
| **ボーナス2** | 10点 | LRUキャッシュが正しく動作する |
| **ボーナス3** | 5点 | マップユーティリティが実装されている |
提出方法
submission/
├── go.mod
├── main.go
├── student/
│ ├── student.go
│ └── student_test.go
├── textanalysis/
│ ├── analysis.go
│ └── analysis_test.go
├── sliceutil/
│ ├── sliceutil.go
│ └── sliceutil_test.go
└── bonus/
├── cache/
└── maputil/
ヒント
- スライスのコピー:
copy()関数またはappend()を使用 - マップの順序: rangeで順序は保証されない
- 容量の事前確保:
make([]T, 0, capacity)でパフォーマンス向上 - nil判定: スライス/マップがnilかチェックする
- sort.Slice: カスタム比較関数でソート可能
- Go Slices: usage and internals
- Go maps in action
- Effective Go - Data structures
- sort package