# מערכים מול ⁦List<T>⁩📖 שיעור

## מה זה?

משתנה בודד מחזיק ערך אחד — אבל מה קורה כשצריך לשמור 50 שמות של תלמידים? להצהיר 50 משתנים נפרדים (`name1`, `name2`, ...) זה בלתי אפשרי לתחזוקה. מערכים (`array`) ו-`List<T>` פותרים את זה: שני סוגי אוסף שמחזיקים כמה ערכים תחת "משתנה" אחד — אבל עם הבדל קריטי: מערך נעול בגודלו מרגע היצירה, בעוד `List<T>` יכול לגדול ולהתכווץ דינמית.

## מילות מפתח שחשוב לזכור

• Array (`int[]`) — אוסף בגודל **קבוע**, נקבע ברגע היצירה ולא ניתן לשינוי

• `List<T>` — אוסף **דינמי**; אפשר להוסיף (`Add`) ולהסיר (`Remove`) איברים בזמן ריצה

• Index — המיקום של איבר באוסף, מתחיל תמיד מ-`0`

• `Length` (למערך) / `Count` (ל-`List<T>`) — כמה איברים יש כרגע באוסף

• `IndexOutOfRangeException` — שגיאת ריצה כשמנסים לגשת לאינדקס שלא קיים באוסף

```csharp
// Array — fixed size from the moment of creation
int[] scores = new int[3] { 90, 85, 78 };
Console.WriteLine(scores[0]);       // 90 — index starts from 0
Console.WriteLine(scores.Length);   // 3
// scores[3] = 100;                 // IndexOutOfRangeException — there's no fourth slot

// List<T> — grows and shrinks at runtime
List<string> names = new List<string> { "Dana", "Avi" };
names.Add("Rotem");        // now 3 items
names.Remove("Avi");      // now 2 items — "Dana", "Rotem"
Console.WriteLine(names.Count);   // 2
```

```csharp
// foreach — same syntax for both types, exactly
foreach (string name in names)
{
    Console.WriteLine(name);
}
```

## הסבר עיקרי

למה בכלל להשתמש במערך אם `List<T>` גמיש יותר — מערך תופס **פחות זיכרון וריצה מהירה מעט יותר**, כי הגודל שלו ידוע וקבוע מראש; ל-`List<T>` יש overhead ניהולי כדי לתמוך בגדילה דינמית. בפועל: אם יודעים בוודאות שהכמות לא תשתנה (למשל "7 ימים בשבוע"), מערך מתאים. בכל מצב אחר — במיוחד כשלא ברור מראש כמה איברים יהיו — `List<T>` הוא הבחירה הנכונה כמעט תמיד.

`Add`/`Remove` הם מה ש-`List<T>` נותן ומערך לא — זו בדיוק הסיבה ש-`List<T>` נפוץ הרבה יותר בקוד אמיתי: רשימת משימות שמשתמש מוסיף ומוחק ממנה, תוצאות שמצטברות תוך כדי ריצה — כל אלה דורשים גודל שלא ידוע מראש.

Index תמיד מתחיל מ-0 — האיבר הראשון הוא `[0]`, לא `[1]`. זו טעות נפוצה במיוחד למי שבא משפות/הקשרים אחרים — וגישה לאינדקס שלא קיים (למשל `scores[3]` על מערך בגודל 3) זורקת `IndexOutOfRangeException` בזמן ריצה, לא שגיאת קומפילציה.

## יתרונות

מערך יעיל בזיכרון ובביצועים כשהגודל קבוע וידוע; `List<T>` נותן גמישות מלאה להוספה/הסרה בלי לדעת מראש כמה איברים יהיו; שניהם תומכים ב-`foreach` באותו תחביר בדיוק, כך שקל להחליף ביניהם.

## חסרונות

מערך לא ניתן לשינוי גודל אחרי היצירה — צריך ליצור מערך חדש ולהעתיק אם רוצים "להוסיף" איבר; `List<T>` עם overhead ניהולי קטן שגורם לו להיות מעט פחות יעיל ממערך בתרחישי ביצועים קריטיים מאוד.

## נקודות חשובות

• מערך — גודל קבוע מרגע היצירה; `List<T>` — גודל דינמי, תומך ב-`Add`/`Remove`

• אינדקס תמיד מתחיל מ-`0`; אינדקס לא קיים זורק `IndexOutOfRangeException` בזמן ריצה

• `Length` שייך למערך, `Count` שייך ל-`List<T>` — שמות שונים לאותו רעיון

• `List<T>` היא ה-Generic הראשון שנתקלים בו — `T` הוא placeholder לטיפוס (`List<string>`, `List<int>`)

## טעויות נפוצות

• לנסות "להוסיף" איבר למערך קיים ישירות (`array[3] = x` על מערך בגודל 3) — צריך מערך גדול יותר או `List<T>`

• לבלבל בין `Length` (מערך) ל-`Count` (`List<T>`) ולקבל שגיאת קומפילציה

• לגשת לאיבר לפי אינדקס בלי לבדוק שהוא בטווח, ולקבל `IndexOutOfRangeException` בזמן ריצה בלתי צפוי

## סיכום

מערך ו-`List<T>` שניהם מחזיקים כמה ערכים תחת משתנה אחד, אבל מערך נעול בגודל קבוע מרגע היצירה בעוד `List<T>` גדל ומתכווץ דינמית עם `Add`/`Remove`. כברירת מחדל, כשלא ברור מראש כמה איברים יהיו — `List<T>` הוא הבחירה הנכונה; מערך שמור למקרים שבהם הגודל קבוע וידוע מראש.

## דוקומנטציה רשמית

[Microsoft Learn — Arrays](https://learn.microsoft.com/dotnet/csharp/programming-guide/arrays/)

[Microsoft Learn — List&lt;T&gt;](https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1)

---

## תרגילים

### תרגיל 1 — סכום מערך

**המשימה:** צרו מערך `int[]` עם 5 מספרים, וחשבו עם `foreach` את סכומם הכולל.

**בדיקה:** המערך `{1, 2, 3, 4, 5}` מדפיס סכום `15`.

### תרגיל 2 — ניהול רשימת קניות

**המשימה:** צרו `List<string>` ריקה, הוסיפו 4 פריטים עם `Add`, הסירו אחד עם `Remove`, והדפיסו את הרשימה הסופית עם `foreach`.

**בדיקה:** הרשימה הסופית מכילה 3 פריטים — כל מה שנוסף, פחות מה שהוסר.

---

## פרויקט מסכם

**המשימה:** כתבו תוכנית "ניהול תלמידים" שמאחסנת ציונים ומחשבת עליהם סטטיסטיקות בסיסיות.

**דרישות:**
1. `List<int>` שמתחילה ריקה, וממלאים אותה בלולאה עם 5 ציונים מהמשתמש (`Console.ReadLine` + `int.TryParse`)
2. חישוב ממוצע (`Sum()` חלקי `Count`), ציון מקסימלי ומינימלי (מותר שימוש ב-`Max()`/`Min()` אם מוכרים, או חישוב ידני עם לולאה)
3. הדפסת כל שלוש הסטטיסטיקות בסיום

**בדיקה:** קלט `{80, 90, 70, 100, 60}` מדפיס ממוצע `80`, מקסימום `100`, מינימום `60`.

## מה בפרק הבא

בפרק הבא — **פונקציות**: איך אורזים לוגיקה חוזרת לבלוק אחד שקוראים לו בשם, במקום להעתיק-הדבק את אותו קוד בכמה מקומות.
