numbers += string.Format("(number = {0}) OR ", i);
}
numbers = numbers.Remove(numbers.Length - 4);
בו משרשרים הרבה מחרוזות עם איזשהו מפריד ביניהן.
בדרך כלל האיטרציה היא על איזשהו IEnumerable ולאו דווקא כפי שעשיתי.
הבעיה בסיפור הזה היא שהסיבוכיות כאן היא $ o(n^2) $, כי כל איטרציה אנחנו יוצרים אובייקט חדש ובעצם מעתיקים את כל האובייקט הקודם כפי שהוא! (הרי ידוע שstring הוא Immutable)
בנוסף עצם העובדה שבסוף אנחנו צריכים להסיר את האובייקט האחרון רק מכבידה על העניין.
יבואו הצדיקים ויאמרו, השתמש בStringBuilder. כך נראה הקוד עם StringBuilder:
1
2
3
4
5
6
7
8
StringBuilder numbers = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
numbers.AppendFormat("(number = {0}) OR ", i);
}
numbers = numbers.Remove(numbers.Length - 4, 4);
כעת הסיבוכיות היא $ o(n) $, עם זאת עדיין משהו פה לא כל כך יפה.
הפתרון: השתמשו בstring.Join:
1
2
3
4
5
6
7
8
List<string> numbersList = new List<string>(1000);
string numbers = string.Join(" OR ", numbersList.ToArray());
הערה:
גם פה יש משהו שהוא קצת לא יפה, כיוון שצריך לעשות ToArray בשביל הפונקציה string.Join. אישית אני לא חושב שזה כל כך נורא, וזה יותר קריא משתי הדוגמאות הקודמות (שם לא כל כך ברור מיידית מתי צריך להסיר את השרשור האחרון).
אפשר לפתור את הבעיה אם אתם משתמשים בFramework 4, אז יש overloadים חדשים לstring.Join. ביניהם יש גם overload שמקבלIEnumerable<T>,המבצע פשוט Join של הToString() של כל אובייקט בIEnumerable.
כך יראה הקוד בnet 4:
1
2
3
4
5
6
7
8
List<string> numbersList = new List<string>(1000);
היתרון הוא שהכתיבה הראשונה היא בזבזנית, מאחר והיא יוצרת אובייקטים חדשים רק בשביל להשוות מחרוזות. הכתיבה השנייה משווה מחרוזות קיימות מבלי להקצות אובייקטים חדשים. ראו גם טיפ על StringComparer (טיפ מספר 113)