לולאות – for ו – foreach הן לולאות נפוצות בשימוש אצל מתכנתי – #C, כאשר על מנת לבצע איטרציה על אוספים, לדעתם של לא מעט מתכנתים ,לולאת ה-foreach היא פתרון נוח יותר, אך לפתרון זה מתלווה חסרון בולט – אין לנו אינדקסים בניגוד ללולאת – for פשוטה
בלולאת – for פשוטה ניתן בלי שום בעיה לבצע אופרציות מבוססות אינדקסים, אנו הרי מגדירים משתנה זמני (איטרטור, במקרה הזה קראנו לו – i) בחתימת הלולאה:
// normal for loop for (int i = 0; i < collection.Count; i++;) { var item = collection[i]; DoSomething(item, i); }
כלומר שאם היינו מעוניינים לבצע פעולה דומה באמצעות לולאת – foreach היינו צריכים להוסיף – index באופן ידני, פעולה אמנם לא מסובכת, אך לא בהכרח "נקייה":
// foreach loop with manual index int i = 0 forech (var item in collection) { DoSomething(item, i); i++; }
כמובן שכאשר מדובר בתוכנית קטנה פתרון זה יספיק לנו, אך במצבים שבהם אנו כותבים תוכנית גדולה שמנצלת הרבה משאבי זיכרון ומנהלת מספר גדול של משתנים, נחתור להיות חסכוניים בקוד , כלומר נשתדל שלא ליצור משתנה אינדקס לכל לולאת – foreach מכיוון שיש בנמצא פתרונות יותר טובים לנושא.
כידוע ניתן לבצע שאילתות -LINQ על כל מה שמממש את האינטרפייס – IEnumerable, אם זה כך, יש פתרון נוסף לבעיה שלנו, שימו לב לפונקציית ההרחבה הבאה:
using System.Linq; public static IEnumerable<(T item, int i)> WithIndex<T>(this IEnumerable<T> source) { return source.Select((item, i) => (item, i)); }
כעת נוכל להשתמש באינדקסים בלולאת ה-foreach שלנו כך:
foreach (var (item, i) in collection.WithIndex()) { DoSomething(item, i); }
כמו כן, אם מדובר דווקא במבנה נתונים מסוג – <List<T, אז הפתרון יהיה אפילו יותר פשוט, משום שנוכל להשתמש בפונקציה – ()indexOf על מנת שנוכל לקבל את האינדקס הנוכחי:
foreach (Object o in collection) { i = collection.indexOf(o); }
אך עם זאת חשוב מאוד לשים לב כי זה אינו תחליף אמיתי לאינדקס, משום שאם הרשימה תכיל ערך זהה יותר מפעם אחת, פתרון זה כבר לא יוכל להיות רלוונטי, משום שהמתודה indexOf לא בהכרח תחזיר לנו את האינדקס הנכון במקרה כזה.