Menu
CoddyTech

全体のまとめ

CoddyのGOジャーニー「論理とフロー」セクションの一部。レッスン 50/68。

challenge icon

チャレンジ

簡単

前のレッスンで作成したすべての機能を統合する包括的なメインプログラムを作成し、在庫管理システムを完成させましょう。この最終課題では、在庫の初期化、在庫数の確認、商品の追加、在庫数の更新、レポートの生成を組み合わせ、メニュー形式の操作で利用できる完全なコマンドラインインターフェースを作成します。

次の3つの入力を受け取ります。

  • "product1:price1:quantity1,product2:price2:quantity2,product3:price3:quantity3"形式の初期在庫データを含む文字列(例:"Laptop:999.99:5,Mouse:25.50:15,Keyboard:75.00:8")
  • メニュー操作のシーケンスを含む文字列。形式は"operation1,operation2,operation3"で、操作には"check"、"add"、"update"、"report"、または"exit"を指定できます(例:"check,add,update,report,exit")
  • "param1|param2|param3"形式の操作パラメーターを含む文字列。各パラメーターは同じ位置にある操作に対応します(例:"Mouse|Monitor:299.99:10|Laptop:5|full,10")

課題:

  1. 前のレッスンと同じProduct構造体を使用します。フィールドはPrice(float64)とQuantity(int)です。
  2. 最初の入力を解析し、既存の商品データを使って在庫マップを初期化します。
  3. システム起動メッセージを表示します。
    • "=== INVENTORY MANAGEMENT SYSTEM ==="
    • "System initialized with [number_of_products] products"
    • "Starting interactive session..."
  4. 2番目の入力を解析し、実行する操作のシーケンスを取得します。
  5. 3番目の入力を解析し、各操作のパラメーターを取得します。
  6. シーケンス内の各操作について、操作のヘッダーを表示し、対応する処理を実行します。
    • "check"の場合:"--- STOCK CHECK ---"を表示し、指定された商品の在庫を確認します。
    • "add"の場合:"--- ADD ITEM ---"を表示し、指定された商品を追加します。
    • "update"の場合:"--- UPDATE STOCK ---"を表示し、指定された商品の在庫数を更新します。
    • "report"の場合:"--- GENERATE REPORT ---"を表示し、指定されたレポートを生成します。
    • "exit"の場合:"--- SYSTEM EXIT ---"を表示し、終了情報を表示します。
  7. 前のレッスンと同様に、数量とエラーを返すcheckStock関数を実装します。
  8. 前のレッスンと同様に、商品を追加してエラーを返すaddNewItem関数を実装します。
  9. 前のレッスンと同様に、数量を更新してエラーを返すupdateStock関数を実装します。
  10. 以下の"report"操作で説明するレポートを出力するgenerateReport関数を実装します。
  11. "check"操作の場合:
    • パラメーターを確認対象の商品の名前として使用します。
    • "Checking stock for: [product_name]"と表示します。
    • 商品が見つかった場合:"Stock level: [quantity] units"
    • 商品が見つからない場合:"Product not found in inventory"
  12. "add"操作の場合:
    • "product_name:price:quantity"形式のパラメーターを解析します。
    • "Adding new product: [product_name]"と表示します。
    • 成功した場合:"Product added successfully"
    • 失敗した場合:"Failed to add product: [error_message]"と表示します。エラーは"product already exists"です。
  13. "update"操作の場合:
    • "product_name:change"形式のパラメーターを解析します。
    • "Updating stock for: [product_name]"と表示します。
    • 更新に成功し、changeが0以上の場合:"Added [change] units. New stock: [new_quantity]"
    • 更新に成功し、changeが負の場合:"Removed [absolute_change] units. New stock: [new_quantity]"
    • 失敗した場合:"Update failed: [error_message]"と表示します。エラーは"product not found"、または新しい数量が0未満になる場合は"insufficient stock"です。
  14. "report"操作の場合:
    • "report_type,threshold"形式のパラメーターを解析します。report_typeは"low"または"full"、thresholdは整数です。
    • "Generating [report_type] report with threshold [threshold]"と表示します。
    • その後、商品をアルファベット順に並べてレポートを出力します。
      • "low"の場合:"=== LOW REPORT ==="、次に"Products with stock below [threshold]:"、続いて数量がthreshold未満の各商品について"- [name]: [quantity] units (Price: $[price])"を出力します。
      • "full"の場合:"=== FULL REPORT ==="、次に"Complete inventory (minimum threshold: [threshold]):"、続いてすべての商品について"- [name]: [quantity] units @ $[price] each [OK]"を出力します。数量がthreshold未満の場合は、[OK]の代わりに[LOW STOCK]を使用します。
  15. "exit"操作の場合:
    • 在庫の最終統計を表示します。
      • "Final inventory status:"
      • "Total products: [total_products]"
      • "Total items: [total_items]"
      • "Total value: $[total_value]"
    • "Session completed successfully"と表示します。
    • "Thank you for using the Inventory Management System"と表示します。
  16. 各操作の後(exitを除く)に、"Operation completed. Continuing to next operation..."を表示します。

入力文字列の分割にはstringsパッケージ、文字列から数値への変換にはstrconvパッケージ、エラー処理にはerrorsパッケージ、書式付き出力にはfmtパッケージ、アルファベット順のソートにはsortパッケージを使用します。価格と金額はすべて小数点以下2桁で表示します。この課題では、複数の機能コンポーネントを統合し、適切なエラー処理と状態管理を備えた、一貫性のあるユーザー体験を提供する対話型システムの作成方法を学びます。

自分で試してみよう

package main

import (
	"fmt"
	"sort"
	"strconv"
	"strings"
)

type Product struct {
	Price    float64
	Quantity int
}

func generateReport(inventory map[string]Product, reportType string, threshold float64) {
	// Display report header
	switch reportType {
	case "full":
		fmt.Println("=== FULL INVENTORY REPORT ===")
	case "low_stock":
		fmt.Println("=== LOW STOCK REPORT ===")
	case "high_value":
		fmt.Println("=== HIGH VALUE REPORT ===")
	}

	// Calculate general statistics
	totalProducts := len(inventory)
	totalItems := 0
	totalValue := 0.0
	
	for _, product := range inventory {
		totalItems += product.Quantity
		totalValue += product.Price * float64(product.Quantity)
	}
	
	averagePrice := totalValue / float64(totalItems)

	// Display general statistics
	fmt.Printf("Total Products: %d\n", totalProducts)
	fmt.Printf("Total Items in Stock: %d\n", totalItems)
	fmt.Printf("Total Inventory Value: $%.2f\n", totalValue)
	fmt.Printf("Average Product Price: $%.2f\n", averagePrice)

	// Filter products based on report type
	var filteredProducts []string
	for name, product := range inventory {
		switch reportType {
		case "full":
			filteredProducts = append(filteredProducts, name)
		case "low_stock":
			if product.Quantity <= int(threshold) {
				filteredProducts = append(filteredProducts, name)
			}
		case "high_value":
			productValue := product.Price * float64(product.Quantity)
			if productValue >= threshold {
				filteredProducts = append(filteredProducts, name)
			}
		}
	}

	// Sort filtered products alphabetically
	sort.Strings(filteredProducts)

	// Display filtered products section header
	switch reportType {
	case "full":
		fmt.Println("All Products:")
	case "low_stock":
		fmt.Printf("Products with stock ≤ %.0f:\n", threshold)
	case "high_value":
		fmt.Printf("Products with value ≥ $%.2f:\n", threshold)
	}

	// Display filtered products
	filteredItems := 0
	filteredValue := 0.0
	for _, name := range filteredProducts {
		product := inventory[name]
		productValue := product.Price * float64(product.Quantity)
		fmt.Printf("- %s: $%.2f × %d = $%.2f\n", name, product.Price, product.Quantity, productValue)
		filteredItems += product.Quantity
		filteredValue += productValue
	}

	// Display filtered statistics
	fmt.Println("Filtered Results:")
	fmt.Printf("Products shown: %d\n", len(filteredProducts))
	fmt.Printf("Items in filtered products: %d\n", filteredItems)
	fmt.Printf("Value of filtered products: $%.2f\n", filteredValue)

	// Find most and least expensive products
	var mostExpensiveName, leastExpensiveName string
	var mostExpensivePrice, leastExpensivePrice float64
	first := true
	
	var sortedNames []string
	for name := range inventory {
		sortedNames = append(sortedNames, name)
	}
	sort.Strings(sortedNames)
	
	for _, name := range sortedNames {
		product := inventory[name]
		if first {
			mostExpensiveName = name
			mostExpensivePrice = product.Price
			leastExpensiveName = name
			leastExpensivePrice = product.Price
			first = false
		} else {
			if product.Price > mostExpensivePrice {
				mostExpensiveName = name
				mostExpensivePrice = product.Price
			}
			if product.Price < leastExpensivePrice {
				leastExpensiveName = name
				leastExpensivePrice = product.Price
			}
		}
	}

	fmt.Println("Price Analysis:")
	fmt.Printf("Most expensive: %s at $%.2f\n", mostExpensiveName, mostExpensivePrice)
	fmt.Printf("Least expensive: %s at $%.2f\n", leastExpensiveName, leastExpensivePrice)

	// Find highest and lowest stock products
	var highestStockName, lowestStockName string
	var highestStock, lowestStock int
	first = true
	
	for _, name := range sortedNames {
		product := inventory[name]
		if first {
			highestStockName = name
			highestStock = product.Quantity
			lowestStockName = name
			lowestStock = product.Quantity
			first = false
		} else {
			if product.Quantity > highestStock {
				highestStockName = name
				highestStock = product.Quantity
			}
			if product.Quantity < lowestStock {
				lowestStockName = name
				lowestStock = product.Quantity
			}
		}
	}

	fmt.Println("Stock Analysis:")
	fmt.Printf("Highest stock: %s with %d units\n", highestStockName, highestStock)
	fmt.Printf("Lowest stock: %s with %d units\n", lowestStockName, lowestStock)

	// Inventory health assessment
	lowStockCount := 0
	highStockCount := 0
	highValueCount := 0
	
	for _, product := range inventory {
		if product.Quantity <= 5 {
			lowStockCount++
		}
		if product.Quantity > 20 {
			highStockCount++
		}
		productValue := product.Price * float64(product.Quantity)
		if productValue >= 500.0 {
			highValueCount++
		}
	}

	fmt.Printf("Low stock items (≤5): %d\n", lowStockCount)
	fmt.Printf("High stock items (>20): %d\n", highStockCount)
	fmt.Printf("High value items (≥$500): %d\n", highValueCount)

	// Report completion
	fmt.Println("Report generated successfully")
	fmt.Printf("Threshold applied: %.2f\n", threshold)
}

func main() {
	var inventoryData string
	var reportConfig string
	fmt.Scanln(&inventoryData)
	fmt.Scanln(&reportConfig)

	// Parse inventory data
	inventory := make(map[string]Product)
	if inventoryData != "" {
		products := strings.Split(inventoryData, ",")
		for _, productStr := range products {
			parts := strings.Split(productStr, ":")
			name := parts[0]
			price, _ := strconv.ParseFloat(parts[1], 64)
			quantity, _ := strconv.Atoi(parts[2])
			inventory[name] = Product{Price: price, Quantity: quantity}
		}
	}

	// Parse report configuration
	configParts := strings.Split(reportConfig, ",")
	reportType := configParts[0]
	threshold, _ := strconv.ParseFloat(configParts[1], 64)

	// Generate report
	generateReport(inventory, reportType, threshold)
}

論理とフローのすべてのレッスン

自分で練習してみよう: Goオンラインコンパイラ