خب در این ویدیو، یک کالکشن قدیمی دیگه برای شما دارم که می‌تونید ببینید، اما اجباری نیست.
و فقط در صورتی مرتبط هست که تا به حال از کد قدیمی استفاده کرده باشید یا نیاز به نگهداری کد قدیمی داشته باشید، یا صرفاً پروژه‌های قدیمی رو نگاه می‌کنید که کدهایی با استفاده از **Hash Table** نوشته شده‌اند.
این‌ها صرفاً یک نوع کالکشن هستند که جفت **Key-Value** دارن، مشابه چیزی که یک **Dictionary** داره، با این تفاوت که **Dictionary**ها خیلی بهترند چون **Type Safety** دارن،
همچنین **Null Key** و **Concurrency** دارن، و این باعث می‌شه **Dictionary**ها در هر صورت انتخاب بهتری باشن.
بسیار خب، ما در ویدیوهای بعدی عمیقاً به **Dictionary**ها نگاه خواهیم کرد.
اما در حال حاضر، فقط **Hash Table**ها رو تماشا کنید، ریلکس کنید، اگر حوصله‌تون سر رفت، سرعتش رو زیاد کنید، اگر براتون خیلی کنده، یا هر چی.
نیازی نیست همزمان کد بزنید یا هر کار دیگه‌ای.
فقط از مسیر لذت ببرید.
و اگر اصلاً حس تماشای **Hash Table**ها رو ندارید، به ویدیوی بعدی بپرید.
پس **Hash Table** و **Dictionary** برخی از مفیدترین کالکشن‌ها در C# هستند.
پس می‌بینیم که چطور تعریفشون کنیم و چطور استفاده کنیم.
و در چه سناریویی باید ازشون استفاده کنیم.
برای درک مفهوم **Hashing** و **Table**ها، ابتدا به یک دیکشنری واقعی فکر کنید.
پس فرض کنید ما یک دیکشنری آلمانی به انگلیسی داریم، که در اون هر کلمه در آلمانی فقط با یک کلمه در انگلیسی مطابقت داره، چون این محدودیت اینجا خواهد بود.
بنابراین وقتی سعی می‌کنیم کلمه‌ی **"Auto"** رو ترجمه کنیم، که در آلمانی اساساً به **"Car"** ترجمه می‌شه، در انگلیسی از یک کلمه به عنوان کلمه‌ی **Key** استفاده می‌کنیم که مثلاً بتونیم اون رو جستجو کنیم.
و یک ترجمه به عنوان نتیجه دریافت می‌کنیم.
پس همیشه این رابطه‌ی **"یک به یک"** وجود داره.
پس ما **"Auto"** رو داریم و اون به **"Car"** ترجمه می‌شه.
و ما دقیقاً می‌تونیم با استفاده از **Hash Table**ها هم به این برسیم.
و ما قراره از این در یک مثال خیلی خاص اینجا استفاده کنیم.
پس فرض کنید یک سیستم ثبت‌نام دانشجو داریم که در اون هر دانشجو یک **ID** و داده‌های زیادی مثل نام، سن، نمرات، و تصویر و غیره داره.
برای اینکه چنین سیستمی کار کنه، به یک **ID** مخصوص برای هر دانشجو نیاز داریم. پس باید منحصر به فرد باشه.
اگر قرار بود این داده‌ها رو با استفاده از یک **Hash Table** یا **Dictionary** ذخیره کنیم، **Student ID** حکم **Key** رو داشت و داده‌های دانشجو یک **Object** می‌شد که تمام اطلاعات دیگه دانشجو رو در بر می‌گرفت، و اون **Value** می‌شد.
بنابراین ما همیشه این جفت **Key-Value** رو داریم، باشه؟
پس این نحوه پیدا کردن داده‌های واقعی، به اصطلاح، هست.
و این **Value** هست که پشت اون قرار داره.
پس می‌تونید اون رو مثل یک کمد در نظر بگیرید.
پس این **ID** کمد یا مکان کمد هست. می‌تونه انواع مختلفی از داده‌ها باشه. لازم نیست **ID** باشه و این **Value** خواهد بود.
و این **Value** خواهد بود.
پس در **Dictionary** باید از یک نوع باشند.
در یک **Hash Table**، می‌تونن از انواع مختلف باشن.
پس این می‌تونه یک **Integer** باشه و این می‌تونه مثلاً یک **Object** باشه.
پس اول به **Hash Table**ها نگاه می‌کنیم.
بنابراین ما قراره یک **Class** جدید ایجاد کنیم.
یا در واقع من یک **Class** جدید برای این آماده کرده‌ام.
بذارید اینجا پایین بذارمش.
و اون چند تا **Property** داره.
یک **Property ID**، یک **Property Name** و **GPA** داره.
و بعد ما یک **Constructor** خیلی ساده داریم که به سادگی مقدار رو تخصیص می‌ده.
بنابراین هر **ID** که هنگام ایجاد **Student Object** به اون پاس بدیم، **ID** اون **Student Object** خواهد بود و الی آخر.
باشه، پس چیز فانتزی‌ای اینجا نداریم.
فقط داریم از یک **Class** معمولی استفاده می‌کنیم، همونطور که در فصل **Class** پوشش دادیم.
حالا البته می‌تونستیم جلو بریم و این **Class** رو در یک فایل جداگانه ایجاد کنیم، پس می‌تونستیم بریم و **Solution Explorer**مون رو باز کنیم.
بریم جلو و یک فایل جدید اینجا ایجاد کنیم.
پس **Add New Item** یا یک **New Class** مثل این و اون رو **Student** بنامیم.
اما برای این مثال من قراره ساده نگهش دارم و اون رو در یک فایل بذارم.
همونطور که می‌دونید، بهترین کار اینه که اون رو در یک فایل جداگانه بذارید تا چیزها رو با هم قاطی نکنید. و بتونید فایل‌ها و **Class**ها و همه اینها رو راحت‌تر پیدا کنید.
بسیار خب، حالا که **Student Class**مون رو داریم، می‌تونیم جلو بریم و یک **Hash Table** ایجاد کنیم، باشه؟
پس داخل **Program** ما در اینجا در **Main Method**، جاییه که من قراره یک **Hash Table** جدید تعریف کنم.
و به این شکل خواهد بود، **Hash Table**. و من این رو **Table** می‌نامم که یک **New Hash Table** خواهد بود.
**Hash Table Class** داخل **System.Collections** هست.
پس ما باید این **Namespace** رو بالا اضافه کنیم: **using System.Collections**.
پس **Hash Table** و اون با **Hash Tables Namespace** متفاوته چون من کالکشن خودم رو اونطور نامگذاری کردم که ممکنه IDE ما رو اینجا گیج کنه. اگر بخوایم **Hash Table** رو بدون اضافه کردن این **Namespace** به پروژه‌مون وارد کنیم. اما حالا که اون رو داخل **Program Class**مون داریم، می‌تونیم ازش استفاده کنیم.
اما حالا که اون رو داخل **Program Class**مون داریم، می‌تونیم ازش استفاده کنیم.
پس ما این **New Hash Table** رو داریم، که حالا یک **Table** از داده‌ها خواهد بود. و ما می‌تونیم داده‌هایی که می‌خوایم رو داخلش قرار بدیم.
پس این نحوه ایجاد چنین **Hash Table**ی هست. نحوه مقداردهی اولیه اون با یک **Hash Table Object** خالی، همونطور که اینجا انجام دادیم.
خب حالا کاری که می‌تونیم انجام بدیم اینه که می‌تونیم مقادیر رو به این **Hash Table** اختصاص بدیم.
و حتی می‌تونیم اون رو **StudentsTable** بنامیم تا کدمون کمی خواناتر بشه.
بنابراین ما فقط باید تعدادی دانشجو ایجاد کنیم که می‌خوایم در **Table**مون داشته باشیم.
پس بذارید اون‌ها رو هم اینجا اضافه کنم، اون‌ها رو **Student 1، Student 2، Student 3، Student 4** می‌نامم. و همه‌شون **New Student Object** خواهند بود.
پس اینجا این دانشجو با **ID 1**، **Maria** خواهد بود. اون یک **GPA** 98 داره.
بعد ما **Jason** رو داریم که **ID** یک رو خواهد داشت. این **ID** اینجاست، شناسه منحصر به فرد به اصطلاح.
و بعد **GPA** که دانشجوها دارن، باشه.
پس حالا ما همه اون دانشجوها رو داریم و می‌تونیم اون‌ها رو به **StudentsTable**مون با استفاده از **Student ID** اختصاص بدیم.
و یک روش خوب این خواهد بود که بریم جلو و بگیم **StudentsTable.Add**.
و اینجا ما از **Student 1.ID** استفاده می‌کنیم.
پس این یکی اینجا، **Property** رو به عنوان **Key** استفاده می‌کنیم.
پس می‌تونید اینجا ببینید یک **Hash Table** به ما اجازه می‌ده یک **Key** از نوع **Object** داشته باشیم. پس می‌تونه هر نوع **Object**ی به عنوان **Key** باشه.
و می‌تونه یک **Object** اختیاری یا قابل تهی (**Nullable**) به عنوان **Value** باشه. پس می‌تونیم یک **Value** اختصاص بدیم یا می‌تونه **Null** باشه، باشه.
اما ما قراره یک **Value** اختصاص بدیم و اون خود **Student 1** خواهد بود، مثل این، باشه.
پس حالا ما **Student 1** رو به **StudentsTable**مون اضافه کردیم.
و می‌تونیم همین کار رو با دانشجوهای دیگه انجام بدیم.
و برای هر کدوم از **ID**شون استفاده می‌کنیم.
پس بذارید **StudentsTable** رو اینجا برای همه‌شون استفاده کنیم، باشه.
پس حالا این **Hash Table** ماست.
اما چطور می‌تونیم ورودی‌ها رو واکشی کنیم؟
پس چطور می‌تونیم ورودی‌ها رو از **Hash Table**مون بازیابی کنیم؟
خب بیایید به روش‌های مختلفش نگاه کنیم.
پس اولین کاری که می‌تونیم انجام بدیم اینه که فقط یک **Student Object** اینجا ایجاد کنیم.
پس **Student** و این **Object** **storedStudent** نامیده خواهد شد، باشه.
پس من قراره **Student Value** رو از **Table**م بگیرم. پس در این مورد، **Student Table** هست.
**StudentsTable** مثل این.
و اینجا مشابه نحوه دسترسی به اون در یک **Array**. نحوه دسترسی به یک **Value** در یک **Array**، می‌تونم به اون با یک **ID** دسترسی پیدا کنم.
پس اینجا، برای مثال، فرض کنید می‌خوام اون یکی در **ID 1** رو بگیرم، مثل این.
پس اینجا مشکل اینجاست که این **Hash Table** می‌تونه **Value**هایی از نوع **Object** داشته باشه، درسته، همونطور که قبلاً دیدیم.
پس اینجا اگه بریم جلو و متد **Add** رو فراخوانی کنیم، می‌بینید می‌تونیم یک **Key** اختصاص بدیم. اما بعد **Value** از نوع **Object** خواهد بود.
و این به این معنیه که این اینجا از نوع **Object** خواهد بود. اما ما نمی‌تونیم فقط یک نوع **Object** رو به **Student** اختصاص بدیم. باید از نوع **Student** باشه چون این **Stored Student 1** در واقع از نوع **Student** هست، باشه.
پس باید مطمئن بشیم که اون رو اینجا به یک **Student** **Cast** می‌کنیم. و بعد این کار می‌کنه. باشه.
پس ما داریم این **Object** رو به یک **Student** **Cast** می‌کنیم چون می‌دونیم که داخل **StudentsTable** در موقعیت 1. پس در **ID 1**، **Value** در واقع از نوع **Student** خواهد بود، باشه.
پس اینجا می‌تونید **Student** در **ID 1** رو بگیرید. می‌تونید **Student** در **ID 2** رو بگیرید و الی آخر.
اما این فقط به این دلیل کار می‌کنه که می‌دونیم در واقع از این اعداد استفاده می‌کنیم.
پس اگه بخواید اون رو به روش دیگه بگیرید، می‌تونستید **Stored Student 1** رو با **ID** بگیرید. پس حالا این به شما **Value** پشت **Student 1 ID** رو خواهد داد.
پس این اساساً به شما این **Value** اینجا یا این دانشجو رو خواهد داد. و این یکی دقیق‌تره. پس این یکی اینجا چون این چیزیه که ما در این **ID 1** ذخیره می‌کنیم.
پس حالا می‌تونیم بریم جلو و کاری مثل این انجام بدیم که در اون حالا به جای نوشتن **"Hello World"**، قراره در واقع یک چیز مفیدی بنویسیم که در اون **Student ID**، **Name** دانشجو،
و همچنین **GPA** اون رو می‌نویسیم. پس ما قراره از **StoredStudent1.ID** استفاده کنیم.
پس ما **ID** اون، **Name** اون و **GPA** اون رو می‌گیریم. و در این مورد **GPA** اونه و الی آخر چون **Maria** در موقعیت 1 در **ID 1** هست، باشه.
پس بیایید این رو اجرا کنیم و می‌بینید **Student ID** یک، **Name** **Maria** و **GPA** 98 هست. پس اینجا دیدیم چطور می‌تونیم یک **Hash Table** ایجاد کنیم.
این نحوه ذخیره داده‌ها در **Hash Table** هست. در واقع اینجا جاییه که ما داده‌ها رو در یک **Hash Table** ذخیره می‌کنیم.
و بعد این نحوه بازیابی داده‌ها از یک **Hash Table** هست.
پس حالا فرض کنیم می‌خوایم در واقع تمام داده‌های داخل **Hash Table**مون رو چاپ کنیم، و ما یک **Key** خاص در دسترس نداریم.
می‌تونیم به سادگی این کار رو با گرفتن تمام **Key**ها از **Hash Table**مون انجام بدیم.
برای حل این مشکل، ابتدا باید در مورد یک **Struct** به نام **Dictionary Entry** صحبت کنیم. هر وقت ما یک ورودی جدید به **Hash Table**مون اضافه می‌کنیم.
پس جفت **Key-Value** ما و یک **New Dictionary Entry Object** برای ما ایجاد خواهد شد، و اون در **Hash Table** ما درج خواهد شد، که به این معنیه که یک **Hash Table** اساساً یک کالکشن از **Dictionary Entry**هاست.
پس با استفاده از یک **Temporary Object** از **Dictionary Entry**، می‌تونیم از طریق **Hash Table**مون با استفاده از یک حلقه **For Each** بریم.
پس بیایید به این در این مثال خاص اینجا نگاه کنیم که در اون من قراره برم جلو و از یک حلقه **For Each** اینجا استفاده کنم.
و این نوع حلقه **For Each** **Dictionary Entry** خواهد بود. این همون **Struct**ی هست که در موردش صحبت می‌کردم. می‌تونید اینجا ببینید **Struct Dictionary Entry**.
خب **Item Name** که قراره ازش استفاده کنم چیه. من قراره از **Entry** استفاده کنم.
البته می‌تونستید این رو **Student** یا هر چی بنامید چون می‌دونید که ورودی‌ها از نوع **Student** خواهند بود. اما فرض کنید نمی‌دونید.
و می‌تونید اون رو **Entry** هم بنامید. و بعد کالکشنی که می‌خوایم این رو از طریق اون اجرا کنیم یا مقادیر رو ازش بگیریم چیه. و اون **StudentsTable** ما خواهد بود.
پس این یکی **Individual Item** رو با **ID** شناخته شده بازیابی می‌کنه.
و اینجا تمام **Value**ها رو از یک **Hash Table** بازیابی می‌کنه، باشه.
پس یک ورودی داخل **Hash Table** ما از نوع **Dictionary Entry** هست، همونطور که گفتم.
پس این حالا به ما اجازه می‌ده از طریق این **Table**، **StudentsTable** بریم و اساساً مقادیر رو نمایش بدیم.
پس اینجا چون **Entry.Value** یک **Object** رو برمی‌گردونه. می‌تونید اینجا ببینید می‌گه **Object**. اما چیزی که ما برای گرفتن جزئیات دانشجو می‌خوایم، قراره یک **Student Object** باشه.
کاری که باید انجام بدیم، اینه که باید کار زیر رو انجام بدیم.
پس ما یک **Temporary Value** ایجاد می‌کنیم که **Entry Value** ما خواهد بود.
حالا ما همون مشکلی رو داریم که اینجا بالا داشتیم، باشه. که در اون باید این رو به یک **Student** **Cast** کنیم چون اون فقط یک **Object** هست، درسته.
اما ما می‌خوایم از نوع **Student** باشه تا بتونیم به **Student Properties** دسترسی داشته باشیم.
پس چون در غیر این صورت **Entry Value.ID** اینجا **ID** نداره، نمی‌تونم به **ID** اون دسترسی داشته باشم، نمی‌تونم به **Name** اون دسترسی داشته باشم. همه اون چیزها با وجود اینکه داخلش وجود داره.
اما **IDE** ما به سادگی اجازه نمی‌ده چون ابتدا باید مطمئن بشیم که **Value** رو به نوع درست، که قراره نوع **Student** ما باشه، تبدیل یا **Cast** می‌کنیم.
پس حالا ما داریم اون رو **Cast** می‌کنیم. داریم اون رو به طور موقت ذخیره می‌کنیم، و حالا می‌تونیم بریم جلو و مقادیر تکی رو در **Console**مون بنویسیم، مثلاً، یا با استفاده از **Program**مون به هر شکلی که می‌خوایم.
پس اینجا می‌تونیم از **Student ID** با استفاده از **Temp.ID** استفاده کنیم چون **Temp** حالا از نوع **Student** هست و **Student** **ID** **Name** **GPA** داره، و ما می‌تونیم به همه‌ی اون‌ها دسترسی داشته باشیم تا. حالا از طریق کل لیست تمام دانشجوهای ما پیمایش کنیم.
پس بیایید این کار رو سریع انجام بدیم.
بیایید کدمون رو اجرا کنیم و ببینیم این حلقه **For Each** برای ما چیکار می‌کنه.
پس می‌تونید ببینید از طریق اون می‌ره.
می‌گه دانشجو 4 **Steve** هست. دانشجو 3 **Clara** هست، دانشجو 2 **Jason** هست، و 1 **Maria** هست.
پس می‌بینید، از آخر به، خب، از آخرین ورودی شروع می‌کنه و تا اولین ورودی می‌ره.
حالا اگه در این نقطه ندونیم که آیا دانشجو هست یا نه، با وجود اینکه اینجا ما داریم اون رو از قبل به یک دانشجو تبدیل می‌کنیم.
این واقعاً فقط برای اینه که به شما نشون بدیم که یک **Hash Table** واقعاً فقط یک کالکشن از **Dictionary Entry**هاست.
پس بیایید ببینیم چطور می‌تونیم این حلقه **For Each** رو ساده‌تر کنیم.
می‌تونیم اون رو با در واقع گفتن **For Each** که در اون نوع متغیر قراره یک **Student** باشه، **Item Name**، خب می‌تونید اون رو **Student** بنامید، من فقط قراره اون رو **Value** بنامم مثل این که خوبه. و کالکشنی که می‌خوام از طریق اون برم قراره **Table** باشه، خب **StudentsTable.Values**.
پس این **ICollection** از **Hash Table Values** وجود داره.
پس این یک **ICollection** رو برمی‌گردونه که شامل مقادیر در **Hash Table** هست. پس این به ما اجازه می‌ده مستقیماً از طریق مقادیر بریم بدون اینکه اساساً مجبور باشیم کاری که اینجا انجام دادیم رو انجام بدیم، که در اون اون رو تبدیل کردیم، یا در اون اون رو به یک **Student Object** **Cast** کردیم.
پس حالا می‌تونیم فقط بریم جلو و همون کاری که اینجا انجام دادیم رو انجام بدیم.
اما حالا البته، قراره **Value.ID** و الی آخر باشه، چون **Entry** نیست و **Temp** نیست، اما در واقع قراره **Value** باشه، باشه.
چون این چیزیه که این حلقه **For Each** برای هر تکرار به ما می‌ده، که از طریق تمام مقادیری که داریم می‌ره و **Value** قراره مقادیر تکی باشه. که در حال حاضر برای اون تکرار خاص بهش نگاه می‌کنیم.
پس در اولین تکرار **Steve** خواهد بود، بعد **Clara** خواهد بود، بعد **Jason**، بعد **Maria**.
باشه، پس اگه این خط اینجا یا این حلقه **For Each** رو حذف کنیم و دوباره اجراش کنیم، خواهیم دید که همون نتایج رو می‌گیریم.
پس **Steve**، **Clara**، **Jason** و **Maria**، باشه.
پس این یک معرفی سریع به **Hash Table**ها بود.
در ویدیوی بعدی یک چالش کوچک برای شما خواهم داشت که در اون اساساً کد خودتون رو کمی گسترش می‌دید تا **Hash Table**ها رو کمی بهتر درک کنید. و بعد به **Dictionary**ها نگاه خواهیم کرد.