آموزش کار کردن با لیست ها در سی شارپ
سی شارپ کلاس های متنوعی برای کار کردن با لیست ها دارد. آنها رابط IList را پیاده سازی می کنند و محبوب ترین پیاده سازی، لیست جنریک است که اغلب از آن به عنوان List <T> یاد می شود. T نوع اشیاء موجود در لیست را مشخص می کند، و این مزیت را به سیستم اضافه می کند که کامپایلر با بررسی های خود می تواند اطمینان حاصل کند که شما فقط اشیاء از نوع صحیح را به لیست اضافه می کنید – به عبارت دیگر ، لیست <T> از نظر آیتم های به کار رفته؛ بدون اشکال است.
لیست بسیار شبیه به کلاس ArrayList است و پیش از آن که سی شارپ از لیست های جنریک پشتیبانی کند؛ به صورت انتخاب لیست go-to (برو-به) بوده است. بنابراین شما همچنین خواهید دید که این لیست می تواند کارهای مشابه با کارهای Array انجام دهد (که درواقع رابط IList را نیز پیاده سازی می کند) ، اما در بسیاری از مواقع، کار کردن با لیست ساده تر و آسان تر است. به عنوان مثال ، شما نیازی به ایجاد لیستی با اندازه خاص ندارید – در عوض، می توانید فقط آن را ایجاد کنید و دات نت به طور خودکار آن را گسترش می دهد تا همان طور که آیتم ها را اضافه می کنید؛ مقدار آیتم ها را متناسب کند.
همان طور که ذکر شد؛ T برای نشان دادن آیتم ها به کار می رود و برای مشخص کردن نوع اشیائی است که می خواهید لیست شامل آنها باشد. در مثالی که آورده ایم؛ می خواهیم به شما نشان بدهیم که چگونه می توانیم لیستی ایجاد کنیم که باید رشته ها را در بر بگیرد:
List<string> listOfStrings = new List<string>();
به این ترتیب یک لیست خالی ایجاد می شود؛ اما پس از آن؛ اضافه کردن مواردی با استفاده از متد Add بسیار ساده خواهد بود:
listOfStrings.Add(“a string”);
با این حال؛ اگر سعی کنید چیزی را اضافه کنید که یک رشته نیست؛ کامپایلر به سرعت در مورد آن خطا می دهد:
listOfStrings.Add(2);
Error CS1503 Argument 1: cannot convert from ‘int’ to ‘string’
مقداردهی اولیه یک لیست با استفاده از آیتم ها
در مثال بالا، ما فقط یک لیست ایجاد کرده ایم و سپس یک آیتم را به آن اضافه نموده ایم. با این حال؛ سی شارپ در واقع به شما اجازه می دهد تا یک لیست را ایجاد کرده و با استفاده از روشی که مقدار دهی اولیه مجموعه نامیده می شود؛ در همان عبارت؛ آیتم هایی را به آن اضافه کنید.
List<string> listOfNames = new List<string>()
{
“John Doe”,
“Jane Doe”,
“Joe Doe”
};
سینتکس کد نویسی بالا بسیار ساده است: قبل از آنکه طبق معمول عبارت ها با سمیکالن به پایان برسد؛ مجموعه ای از آکولادها را داریم که به نوبه خود؛ لیستی از مقادیری را شامل می شود که می خواهیم از ابتدای لیست نمایش بدهیم. از آنجایی که این لیست، لیستی از رشته ها می باشد؛ اشیاء اولیه ای که ارائه می دهیم، قاعدتاً باید از نوع رشته باشد. با این حال، همانطور که در مثال بعدی نشان خواهم داد؛ دقیقاً همین مسئله را می توان برای لیستی با آیتم های نوع دیگر نیز انجام داد، حتی اگر از کلاس های خودمان استفاده می کنیم.
کار با آیتم ها
برای کار با آیتم های لیست جنریک و نشان دادن آنها به شما؛ چندین روش وجود دارد. در ادامه مثال بزرگتری آورده ایم:
using System;
using System.Collections.Generic;namespace Lists
{
class Program
{
static void Main(string[] args)
{
List<User> listOfUsers = new List<User>()
{
new User() { Name = “John Doe”, Age = 42 },
new User() { Name = “Jane Doe”, Age = 34 },
new User() { Name = “Joe Doe”, Age = 8 },
};for(int i = 0; i < listOfUsers.Count; i++)
{
Console.WriteLine(listOfUsers[i].Name + ” is ” + listOfUsers[i].Age + ” years old”);
}
Console.ReadKey();
}
}class User
{
public string Name { get; set; }public int Age { get; set; }
}
}
بیایید از انتها شروع کنیم؛ که در آن یک کلاس ساده برای حفظ اطلاعات مربوط به کاربر -فقط سن و نام کاربر- را تعریف کرده ایم. با نگاهی به بخش بالایی مثال؛ مشاهده می کنید که ما لیست خود را تغییر داده ایم تا به جای رشته های ساده از کلاس User (کاربر) استفاده کنیم. ما از روش مقداردهی اولیه مجموعه استفاده کرده ایم تا بتوان کاربران را در لیست قرار داد -توجه کنید که سینتکس مشابه قبل است و فقط کمی پیچیده تر شده است زیرا با اشیائی کار می کنیم که کمی از رشته ها پیچیده تر هستند.
زمانی که لیست آماده شد، از حلقه for برای اجرای آن استفاده کرده ایم. برای این که بدانیم حلقه قرار است چندبار تکرار شود؛ از ویژگی count ، که یکی از ویژگی های لیست است؛ استفاده کرده ایم؛ ما با استفاده از سینتکس براکت (برای مثال [listOfUser[i) از طریق ایندکسر لیست؛ به کاربر مورد نظر دسترسی پیدا کرده ایم. زمانی که به کاربر دسترسی پیدا شود؛ نام و سن او در خروجی ظاهر می شود.
اضافه کردن، وارد کردن و حذف کردن آیتم ها
ما تا کنون سعی کردیم یک آیتم واحد را به یک لیست اضافه کنیم؛ اما می توان اقدامات دیگری را نیز در یک لیست انجام داد. قبل از هر چیز؛ می توانید به جای اضافه کردن یک آیتم؛ آن را به لیست وارد کنید -تفاوت اضافه کردن و وارد کردن آیتم ها آن است که در به کار گیری متد Add ؛ آیتم به انتهای لیست اضافه می شود و لی متد Insert به شما اجازه می دهد که یک آیتم را در موقعیت خاصی وارد نمایید. در ادامه مثالی از وارد کردن آیتم به لیست مشاهده می کنید:
List<string> listOfNames = new List<string>()
{
“Joe Doe”
};
// Insert at the top (index 0)
listOfNames.Insert(0, “John Doe”);
// Insert in the middle (index 1)
listOfNames.Insert(1, “Jane Doe”);
ما لیست را فقط با یک مورد شروع می کنیم ، اما سپس دو آیتم دیگر را به آن وارد می کنیم، اولی ابتدا در بالای لیست و دومی در وسط لیست وارد می شود. اولین پارامتر متد Insert ایندکس است که در آن می خواهیم آیتمی را وارد کنیم. مراقب باشید؛ زیرا اگر سعی کنید یک آیتم را در ایندکس۳ وارد کنید؛ در صورتی که لیست آیتم های کمتری داشته باشد؛ یک خطا رخ خواهد داد.
اضافه کردن آیتم های چندتایی
دقیقاً همانطور که متدهای Add و Insert را برای افزودن و درج کردن یک آیتم واحد به کار بردیم، متدهایی نیز برای اضافه کردن و وارد کردن آیتم های چندتایی وجود دارد. این متدها؛ AddRange() و InsertRange() نامیده می شوند و هر نوع مجموعه ای که رابط IEnumerable را به عنوان یک پارامتر پیاده سازی کند؛ می پذیرد – این مجموعه به عنوان مثال؛ می تواند مجموعه ای از آیتم ها یا یک لیست دیگر باشد که می خواهید آیتم های آن را به لیست فعلی خود اضافه نموده یا وارد کنید.
به عنوان نمونه ای از متدهای Range ، بیایید کاری جالب انجام دهیم – ما متد AddRange را با یک مقدار دهنده اولیه ترکیب می کنیم تا با استفاده از یک عبارت واحد؛ چندین آیتم جدید را به لیست موجود اضافه کنیم:
listOfNames.AddRange(new string[] {
“Jenna Doe”,
“Another Doe”
});
ما به سادگی یک آرایه از رشته ها را ایجاد می کنیم و بلافاصله آیتم های آن را به لیست نام های خودمان از مثال قبلی می افزاییم.
حذف کردن آیتم ها
در حال حاضر سه روش وجود دارد که با استفاده از آنها می توانید یک یا چند آیتم را از یک لیست حذف کنید: ()Remove؛ ()RemoveAt و ()RemoveAll .
متد ()Remove فقط یک پارامتر می گیرد و آن آیتمی خواهد بود که می خواهید حذف بکنید. این متد برای لیستی از رشته ها یا اعداد صحیح، انتخاب بسیار خوبی است؛ زیرا شما می توانید به سادگی آیتمی که می خواهید حذف کنید را بنویسید. از سوی دیگر اگر لیستی از اشیاء پیچیده داشته باشید؛ شما باید ابتدا شیء مورد نظر را پیدا کنید؛ تا مرجعی داشته باشید که بتوان آن را به متد ()Remove انتقال داد – بعداً به این موضوع بیشتر خواهیم پرداخت- در ادامه مثالی از چگونگی حذف یک آیتم واحد با به کار گیری متد ()Remove آورده شده است:
List<string> listOfNames = new List<string>()
{
“John Doe”,
“Jane Doe”,
“Joe Doe”,
“Another Doe”
};listOfNames.Remove(“Joe Doe”);
متد ()Remove به سادگی در سرتاسر لیست تکرار می شود؛ تا زمانی که اولین مورد از آن شیء را که برای حذف کردن مشخص نموده اید؛ بیابد؛ سپس آن را حذف می کند – این روش اولین مورد از آن آیتم را حذف کرده و متوقف می شود و اگر بازهم در لیست از آن آیتم وجود داشته باشد؛ حذف نمی شود- . اگر شما آیتمی را برای حذف مشخص کرده باشید که در لیست موجود نباشد؛ خطایی در سیستم رخ نمی دهد. زیرا در صورتی که متد ()Remove بتواند آیتمی را حذف کند؛ عبارت true را باز می گرداند و اگر نتواند آیتمی را حذف کند؛ عبارت false را باز میگرداند.
متد ()RemoveAtاز این واقعیت استفاده می کند که لیست جنریک مبتنی بر ایندکس است؛ زیرا به شما اجازه می دهد تا یک آیتم را بر اساس ایندکس/ موقعیت آن در لیست حذف کنید. به عنوان مثال ، می توانید اولین مورد را از لیست مانند این حذف کنید:
listOfNames.RemoveAt(0);
یا این که با به کارگیری کد زیر؛ آخرین آیتم لیست را حذف نمایید:
listOfNames.RemoveAt(listOfNames.Count – 1);
به این ترتیب؛ دوباره یک آیتم واحد حذف می شود و این بار؛ شما باید هنگام ارائه ی ایندکس آیتمی که می خواهید حذف کنید؛ مراقب باشید – اگر از ایندکسی استفاده کنید که خارج از محدوده باشد (کمتر از ۰ یا بیشتر از شماره آیتم های موجود در لیست یک خطا رخ خواهد داد! بنابراین زمانی که از انجام کارتان مطمئن هستید، ممکن است بخواهید از روش ()removeAt در یک بلوک try-catch استفاده کنید تا از رخ دادن خطاها جلوگیری کنید (دربخش های دیگری با جزئیات؛ توضیح داده شده است). روش ()removeAt هیچ چیزی را بر نمی گرداند، بنابراین شما باید قبل و بعد از فراخوانی این متد، تعداد آیتم های موجود در لیست را بررسی و مقایسه کنید تا بتوانید تصمیم بگیرید که آیا حذف موفقیت آمیز انجام شده است یا خیر. از طرف دیگر، اگر می دانید که یک ایندکس دارید که در این لیست وجود دارد – همیشه باید از آنها اطمینان داشته باشید- پس همیشه می توانید انتظار داشته باشید که ()removeAt موفقیت آمیز باشد.
()removeAll پیچیده ترین متد حذف است، اما می توان گفت که قطعاً قدرتمندترین متد هم می باشد. این متد؛ یک دلیگیت را به عنوان پارامتر یک متد؛ به آن متد اختصاص می دهد و آن متد تصمیم می گیرد که آیا یک آیتم باید حذف شود یا نه؛ و این موضوع را با بازگرداندن عبارت های true یا false به شما نشان می دهد. این متد به شما امکان می دهد تا هنگام حذف آیتم ها، منطق خود را اعمال کنید و همچنین به شما امکان می دهد بیش از یک مورد را همزمان حذف کنید. در مورد دلیگیت ها می توانید در بخش های دیگر این مقاله ی آموزشی بیاموزید؛ زیرا موضوع بسیار گسترده و مهمی است. اکنون می خواهیم درمورد استفاده از متد ()RemoveAll مثالی بزنیم تا بیشتر با به کار گیری آن آشنا شوید.
List<string> listOfNames = new List<string>()
{
“John Doe”,
“Jane Doe”,
“Joe Doe”,
“Another Doe”
};listOfNames.RemoveAll(name =>
{
if (name.StartsWith(“J”))
return true;
else
return false;
});
در این مثال ، ما از یک متد ناشناس استفاده می کنیم ( این متد نیز بیش از حد پیچیده است و نمی توان در اینجا توضیح داده شود، اما در فصل دیگری به آن پرداخته می شود). این متد ناشناس، به عنوان پارامتری برای روش removeAll به کار رفته است. این متد ناشناس ما بسیار ساده است – برای هر آیتم موجود در لیست فراخوانی می شود و پارامتری دارد که name نامیده می شود، که البته آیتم فعلی در حال تکرار است. این متد به این اسم نگاه می کند و اگر با “J” شروع شود، عبارت true برگردانده می شود- در غیر این صورت عبارت false بازگردانده می شود. متد ()removeAll از این پاسخ (true یا false) برای تصمیم گیری در مورد حذف شدن یا نشدن هر مورد استفاده می کند.
مرتب سازی آیتم های لیست
تا کنون آیتم های موجود در لیستی که ما با آنها کار کرده ایم، به ترتیبی که اضافه نمودیم؛ استفاده شده است. با این حال ، شما ممکن است بخواهید موارد را به روشی خاص مرتب کنید، به عنوان مثال ممکن است بخواهید لیست را بر اساس الفبا مرتب کنید. لیست <T> یک متد ()Sort دارد که می توانیم به شکل زیر استفاده کنیم:
List<string> listOfNames = new List<string>()
{
“John Doe”,
“Jane Doe”,
“Joe Doe”,
“Another Doe”
};
foreach (string name in listOfNames)
Console.WriteLine(name);
همان طور که از روی خروجی مشاهده می کنید؛ آیتم های موجود در لیست؛ اکنون بر اساس حروف الفبا مرتب شده اند؛ و اگر بخواهید آنها را از آخر به اول مرتب کنید ( از Z به A)؛ به سادگی می توانید بعد از انجام مرتب سازی؛ از متد ()Reverse استفاده کنید:
listOfNames.Sort();
listOfNames.Reverse();
بنابراین مرتب کردن لیست بسیار ساده می باشد، این طور نیست؟ خوب، می توان گفت مرتب سازی به این دلیل ساده است که می خواهیم لیستی از رشته ها را مرتب کنیم و چارچوب دات نت دقیقاً می داند که چگونه دو رشته را با هم مقایسه کند. اگر لیستی از اعداد هم داشته باشید؛ دات نت می داند که چگونه آن را مرتب سازی کند. از طرف دیگر ، شما ممکن است لیستی از اشیاء سفارشی داشته باشید (چرا که لیست <T> می تواند هر نوع شی ء را شامل شود) که دات نت فرصتی برای اطلاع از چگونگی مقایسه ندارد. برای حل این مشکل راه حل های مختلفی وجود دارد ، به عنوان مثال پیاده سازی رابط IComparable یا استفاده از LINQ (در ادامه این مقاله به بررسی هر دو مورد خواهیم پرداخت) ، اما به عنوان یک راه حل سریع، ما همچنین می توانیم متدی را برای فراخوانی با روش ()Sort برای شما فراهم کنیم تا یاد بگیریم که چگونه دو مورد با هم مقایسه می شوند. به مثال زیر توجه کنید:
using System;
using System.Collections.Generic;namespace ListSort
{
class Program
{
static void Main(string[] args)
{
List<User> listOfUsers = new List<User>()
{
new User() { Name = “John Doe”, Age = 42 },
new User() { Name = “Jane Doe”, Age = 39 },
new User() { Name = “Joe Doe”, Age = 13 },
};
listOfUsers.Sort(CompareUsers);
foreach (User user in listOfUsers)
Console.WriteLine(user.Name + “: ” + user.Age + ” years old”);
}public static int CompareUsers(User user1, User user2)
{
return user1.Age.CompareTo(user2.Age);
}
}public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
}
این مثال یک کد تقریباً طولانی را به مثال ما اضافه کرد؛ اما در واقع چندان پیچیده نیست. اگر از پایین شروع کنیم، یک کلاس User بسیار ساده ایجاد کرده ایم که متشکل از نام و سن کاربر می باشد. در وسط کد نویسی؛ روشی به نام ()CompareUsers را تعریف کرده ایم – این کلاس دو کاربر را به عنوان پارامتر اتخاذ می کند و یک عدد صحیح را برمی گرداند، که نشان می دهد آیا یک آیتم “کوچکتر” ، “مساوی” یا “بزرگتر” است (+۱,۰ یا -۱). این مقادیر با استفاده از روش ()Sort برای جابجایی آیتم ها به کار می روند؛ به صورتی که ترتیب آیتم ها با آنچه می خواهیم؛ مطابقت داشته باشد. در این حالت ، من به سادگی از ویژگی Age برای مقایسه استفاده می کنم، در واقع خروجی لیستی از کاربران می باشد که بر اساس سن آنها مرتب سازی شده است.
خلاصه
این مقاله یکی از طولانی ترین مقاله های موجود در آموزش سی شارپ است؛ اما خوشبختانه با مطالعه این بخش می توانید در مورد لیست ها مطالب زیادی بیاموزید؛ زیرا بیشتر با برنامه نویسی آشنا شده اید و می توانید درک کنید که چقدر لیست ها و دیکشنری ها می توانند اهمیت داشته باشند. در فصل بعدی به دیکشنری ها می پردازیم.
بسیااااااار عالی
پاسخعالی بود و بسیار شیوه آموزش خوب بود
پاسخ