課題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/

ヒント