Menu
Coddy logo textTech

在庫数の更新

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

challenge icon

チャレンジ

簡単

包括的なバリデーションとエラーハンドリングを備えた在庫数更新機能を実装することで、在庫管理システムを強化しましょう。このチャレンジは、以前の機能をベースにしており、既存の製品数量を変更する機能を追加しつつ、在庫がマイナスになるような無効な操作を防止します。

2つの入力を受け取ります:

  • 既存の在庫データを含む文字列。形式は "product1:price1:quantity1,product2:price2:quantity2,product3:price3:quantity3" です(例:"Laptop:999.99:5,Mouse:25.50:15,Keyboard:75.00:8")。
  • 在庫更新リクエストを含む文字列。形式は "product1:change1,product2:change2,product3:change3" で、変更値は正または負の整数です(例:"Mouse:10,Tablet:-5,Keyboard:-3")。

あなたのタスクは以下の通りです:

  1. 以前のレッスンと同じ、Price (float64) と Quantity (int) フィールドを持つ Product 構造体を使用します。
  2. 最初の入力をカンマで分割して、個々の既存製品エントリを取得し、解析します。
  3. 各製品エントリをコロンで分割して、製品名、価格、数量を取得します。
  4. 価格の文字列を float64 に、数量の文字列を int に変換します。
  5. 既存の製品データを使用して inventory マップを作成し、データを格納します。
  6. inventory マップ、製品名、数量の変更値をパラメータとして受け取り、エラーを返す updateStock という関数を作成します:
    • 製品が在庫に存在しない場合は、"product not found: [product_name]" というメッセージとともにエラーを返します。
    • 数量の変更によって在庫がマイナスになる場合(現在の数量 + 変更値 < 0)、"insufficient stock: cannot reduce [product_name] by [absolute_change_value], only [current_quantity] available" というメッセージとともにエラーを返します。
    • 更新が有効な場合は、在庫内の製品数量を修正し、nil を返します。
  7. 2番目の入力をカンマで分割して、在庫更新リクエストのリストを取得し、解析します。
  8. 各更新リクエストをコロンで分割して、製品名と数量の変更値を取得します。
  9. 数量の変更値の文字列を int に変換します。
  10. 更新プロセスのヘッダーを表示します:"Processing Stock Updates:"
  11. 各更新リクエストに対して updateStock 関数を呼び出し、結果を表示します:
    • エラーがなく、変更値が正の場合:"[product_name]: Added [change] units - New stock: [new_quantity]"
    • エラーがなく、変更値が負の場合:"[product_name]: Removed [absolute_change_value] units - New stock: [new_quantity]"
    • エラーがなく、変更値がゼロの場合:"[product_name]: No change - Current stock: [current_quantity]"
    • エラーが発生した場合:"[product_name]: Update failed - [error_message]"
  12. 更新の統計をカウントして表示します:
    • "Update Summary:"
    • "Updates processed: [total_number_of_updates_processed]"
    • "Updates successful: [number_of_successful_updates]"
    • "Updates failed: [number_of_failed_updates]"
  13. 更新された在庫を製品名のアルファベット順に表示します:
    • "Updated Inventory:"
    • 各製品について:"- [product_name]: $[price] (Stock: [quantity])"
  14. 最終的な在庫統計を計算して表示します:
    • "Final Inventory Statistics:"
    • "Total Products: [total_number_of_products_in_inventory]"
    • "Total Items in Stock: [sum_of_all_quantities]"
    • "Total Inventory Value: $[sum_of_price_times_quantity_for_all_products]"
  15. 失敗した更新をリストアップします:
    • 失敗した更新がある場合:"Failed updates: [comma_separated_list_of_failed_product_names]"
    • 失敗した更新がない場合:"All stock updates were processed successfully"

入力文字列の分割には strings パッケージ、文字列から数値への変換には strconv パッケージ、エラーメッセージの作成には errors パッケージ、フォーマットされた出力には fmt パッケージ、製品名のアルファベット順のソートには sort パッケージを使用してください。すべての価格と総在庫額は小数点以下2桁までフォーマットしてください。このチャレンジでは、包括的なバリデーションとエラーハンドリングを通じて、無効な操作を防ぎながら既存のデータを安全に修正する方法を学びます。

自分で試してみよう

package main

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

type Product struct {
	Price    float64
	Quantity int
}

func addNewItem(inventory map[string]Product, productName string, price float64, quantity int) error {
	if _, exists := inventory[productName]; exists {
		return errors.New("product already exists: " + productName)
	}
	inventory[productName] = Product{Price: price, Quantity: quantity}
	return nil
}

func main() {
	var existingInventory string
	var newProducts string
	fmt.Scanln(&existingInventory)
	fmt.Scanln(&newProducts)

	inventory := make(map[string]Product)

	// Parse existing inventory
	existingItems := strings.Split(existingInventory, ",")
	for _, item := range existingItems {
		parts := strings.Split(item, ":")
		name := parts[0]
		price, _ := strconv.ParseFloat(parts[1], 64)
		quantity, _ := strconv.Atoi(parts[2])
		inventory[name] = Product{Price: price, Quantity: quantity}
	}

	// Parse new products to add
	newItems := strings.Split(newProducts, ",")
	
	fmt.Println("Adding New Items:")
	
	itemsProcessed := 0
	itemsAdded := 0
	itemsRejected := 0
	var rejectedProducts []string

	for _, item := range newItems {
		parts := strings.Split(item, ":")
		name := parts[0]
		price, _ := strconv.ParseFloat(parts[1], 64)
		quantity, _ := strconv.Atoi(parts[2])
		
		itemsProcessed++
		
		err := addNewItem(inventory, name, price, quantity)
		if err != nil {
			fmt.Printf("%s: Failed to add - %s\n", name, err.Error())
			itemsRejected++
			rejectedProducts = append(rejectedProducts, name)
		} else {
			fmt.Printf("%s: Successfully added - $%.2f (Stock: %d)\n", name, price, quantity)
			itemsAdded++
		}
	}

	// Addition summary
	fmt.Println("Addition Summary:")
	fmt.Printf("Items processed: %d\n", itemsProcessed)
	fmt.Printf("Items added: %d\n", itemsAdded)
	fmt.Printf("Items rejected: %d\n", itemsRejected)

	// Display updated inventory in alphabetical order
	fmt.Println("Updated Inventory:")
	var productNames []string
	for name := range inventory {
		productNames = append(productNames, name)
	}
	sort.Strings(productNames)

	totalProducts := 0
	totalItems := 0
	totalValue := 0.0

	for _, name := range productNames {
		product := inventory[name]
		fmt.Printf("- %s: $%.2f (Stock: %d)\n", name, product.Price, product.Quantity)
		totalProducts++
		totalItems += product.Quantity
		totalValue += product.Price * float64(product.Quantity)
	}

	// Final inventory statistics
	fmt.Println("Final Inventory 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)

	// List rejected products
	if len(rejectedProducts) > 0 {
		fmt.Printf("Rejected products: %s\n", strings.Join(rejectedProducts, ","))
	} else {
		fmt.Println("All new products were added successfully")
	}
}

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