Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

واجهة sort.Interface

جزء من قسم Object Oriented Programming في رحلة GO على Coddy — الدرس 74 من 107.

توفر حزمة sort مثالاً ممتازاً آخر للتصميم القائم على الواجهات (interface-based design). لفرز مجموعة مخصصة، يجب أن يطبق نوعك الواجهة sort.Interface:

type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

توفر هذه الطرق الثلاث لخوارزمية الفرز كل ما تحتاجه: طول المجموعة، وطريقة لمقارنة العناصر، وطريقة لتبديلها. إليك كيفية جعل شريحة (slice) من الهياكل المخصصة (custom structs) قابلة للفرز:

type Person struct {
    Name string
    Age  int
}

type ByAge []Person

func (a ByAge) Len() int           { return len(a) }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func (a ByAge) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

func main() {
    people := []Person{
        {"Alice", 30},
        {"Bob", 25},
        {"Carol", 35},
    }
    
    sort.Sort(ByAge(people))
    fmt.Println(people)
    // [{Bob 25} {Alice 30} {Carol 35}]
}

الفكرة الأساسية هي إنشاء نوع مسمى (ByAge) بناءً على الشريحة (slice) الخاصة بك. يتيح لك هذا تحديد سلوكيات فرز مختلفة لنفس البيانات. يمكنك إنشاء ByName بتنفيذ مختلف لـ Less للفرز أبجديًا بدلاً من ذلك.

بمجرد أن يستوفي النوع الخاص بك sort.Interface، فإنه يعمل مع sort.Sort() و sort.Reverse() و sort.IsSorted() تلقائياً.

challenge icon

التحدي

سهل

لنقم ببناء نظام مخزون منتجات قابل للفرز يوضح قوة sort.Interface في لغة Go! ستقوم بإنشاء نوع Product وتنفيذ استراتيجيات فرز متعددة، مما يسمح بفرز نفس المجموعة بطرق مختلفة.

ستقوم بتنظيم الكود الخاص بك عبر ملفين:

  • product.go: حدد نوع المنتج الخاص بك وتنفيذات الفرز.

    قم بإنشاء هيكل Product بثلاثة حقول: Name (string)، و Price (float64)، و Quantity (int).

    قم بإنشاء نوعين مسميين بناءً على []Product:

    • ByPrice - لفرز المنتجات حسب السعر بترتيب تصاعدي
    • ByQuantity - لفرز المنتجات حسب الكمية بترتيب تنازلي (الكمية الأعلى أولاً)

    يحتاج كل نوع إلى تنفيذ الطرق الثلاث المطلوبة بواسطة sort.Interface: وهي Len()، و Less(i, j int)، و Swap(i, j int). تحدد طريقة Less ترتيب الفرز لكل نوع.

  • main.go: بناء وفرز مخزون المنتجات الخاص بك.

    اقرأ وضع الفرز (price أو quantity)، ثم اقرأ عدداً متبوعاً بتفاصيل المنتج. يتم توفير كل منتج في ثلاثة أسطر: الاسم، والسعر، والكمية.

    قم بإنشاء شريحة (slice) من المنتجات، وقم بفرزها باستخدام نوع الفرز المناسب بناءً على الوضع، ثم اطبع كل منتج بهذا التنسيق:

    [Name]: $[Price] (x[Quantity])

    اعرض الأسعار بمنزلتين عشريتين.

سيتم توفير المدخلات التالية:

  • السطر 1: وضع الفرز (price أو quantity)
  • السطر 2: عدد المنتجات
  • الأسطر التالية: تفاصيل المنتج (الاسم، السعر، الكمية - ثلاثة أسطر لكل منتج)

على سبيل المثال، إذا كان المعطى:

price
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25

يجب أن يكون مخرجك:

Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)

وإذا كان المعطى:

quantity
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25

يجب أن يكون مخرجك:

Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)

لاحظ كيف يمكن فرز نفس بيانات المنتج بشكل مختلف ببساطة عن طريق استخدام نوع مسمى مختلف. بمجرد أن تستوفي أنواعك sort.Interface، فإنها تعمل بسلاسة مع sort.Sort() من المكتبة القياسية.

ورقة مرجعية

تتطلب حزمة sort من الأنواع تنفيذ sort.Interface لتكون قابلة للفرز:

type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

لجعل شريحة (slice) مخصصة قابلة للفرز، قم بإنشاء نوع مسمى وقم بتنفيذ الطرق الثلاث المطلوبة:

type Person struct {
    Name string
    Age  int
}

type ByAge []Person

func (a ByAge) Len() int           { return len(a) }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func (a ByAge) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

// فرز المجموعة
sort.Sort(ByAge(people))

يمكنك إنشاء أنواع مسمّاة متعددة لنفس الشريحة لتنفيذ سلوكيات فرز مختلفة. يحدد كل نوع طريقة Less الخاصة به لتحديد ترتيب الفرز.

بمجرد أن يستوفي النوع sort.Interface، فإنه يعمل مع sort.Sort() و sort.Reverse() و sort.IsSorted().

جرّب بنفسك

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// قراءة وضع الترتيب
	var mode string
	fmt.Fscanln(reader, &mode)

	// قراءة عدد المنتجات
	var count int
	fmt.Fscanln(reader, &count)

	// قراءة المنتجات
	products := make([]Product, count)
	for i := 0; i < count; i++ {
		name, _ := reader.ReadString('\n')
		name = name[:len(name)-1] // إزالة سطر جديد

		priceStr, _ := reader.ReadString('\n')
		priceStr = priceStr[:len(priceStr)-1]
		price, _ := strconv.ParseFloat(priceStr, 64)

		qtyStr, _ := reader.ReadString('\n')
		qtyStr = qtyStr[:len(qtyStr)-1]
		quantity, _ := strconv.Atoi(qtyStr)

		products[i] = Product{Name: name, Price: price, Quantity: quantity}
	}

	// TODO: فرز المنتجات بناءً على الوضع (mode)
	// إذا كان الوضع "price"، استخدم نوع ByPrice
	// إذا كان الوضع "quantity"، استخدم نوع ByQuantity
	// استخدم sort.Sort() مع النوع المناسب

	// TODO: اطبع كل منتج بالتنسيق التالي:
	// [Name]: $[Price] (x[Quantity])
	// استخدم fmt.Printf مع %.2f لتنسيق السعر
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming