درس پانزدهم : لیست ها و دیکشنری ها
درس پانزدهم : لیست ها و دیکشنری ها
15-1 مقدمه
برای ذخیره سازی داده در برنامه، راههای زیادی وجود دارد. برنامه نویس باید بسته به هدف خود و نیاز برنامه از روش صحیح بهره گیرد. برای مثال گاهی فقط یک متغیر برای ذخیره سازی یک داده کوچک کافی ست. زمانی که تعداد داده های همنوع زیاد شود از آرایه ها استفاده میکنیم. با متغیر ها و آرایه ها آشنا هستید. در این درس به بررسی چند روش ذخیره سازی دیگر می پردازیم. زمانی که ذخیره سازی استتیک داده به روشی که در آرایه ممکن است برای ما و برنامه کافی نیست یا داده های پیچیده تر و مرتبط با یکدیگر داریم، باید به سراغ روشهای پیشرفته تر از تعریف متغیر و آرایه های معمولی برویم. در این درس با ArrayList, Dictionary آشنا میشوید.
15-2 ()ArrayList
لیست ها نسخه ی دینامیک آرایه ها هستند. ابتدا ببینیم اصلا کلمات استتیک و دینامیک چه مفهومی دارند. اگر خاطرتان باشد، سینتکس تعریف آرایه به صورت زیر بود:
Dim myArray(10) As Integer
در تعریف آرایه تعیین سایز آرایه درون پرانتز ها الزامی است. در روش دیگر تعریف آرایه محتویات آرایه موقع تعریف آن به آرایه انتساب داده میشود. این یعنی باز هم سایز آرایه یک مقدار مشخص و ثابت تعیین میشود. پس از تعریف آرایه امکان اضافه کردن سایز یا کاهش سایز آرایه وجود ندارد. همچنین برای آرایه ها باید نوع داده را تعیین کنیم و پس از تعریف فقط همان نوع داده ی مشخص شده باید درون آرایه قرار بگیرد. مثلا در مثال بالا سایز آرایه 10 و از نوع عدد صحیح تعریف شده است. این موضوع برای آرایه های یک بعدی یا چند بعدی صدق میکند. در این حالت میگوییم آرایه ها استتیک هستند. یعنی نوع داده شان ثابت و سایزشان غیر قابل تغییر است. این ویژگی آرایه ها گستره ی استفاده از آنان را محدود میکند. برای مثال در بسیاری موارد، ما از تعداد یا نوع داده هایی که قرار است در رانتایم (موقع اجرای برنامه) وارد آرایه شوند، مطلع نیستیم. باید آرایه ای داشته باشیم که فقط تعریف شود و سپس هر زمانی احتیاج بود داده ها را وارد آن کنیم یا از آن حذف کنیم بدون اینکه نگران سایز یا جنس داده ها باشیم. در این حالت به لیست ها میتوانیم رجوع کنیم. به همین علت است که میگوییم لیست ها داینامیک هستند.
15-2-1 سینتکس ArrayList
سینتکس لیست ها به صورت زیر است:
Dim myList As ArrayList = New ArrayList()
سینتکس بالا ممکن است برای شما کمی متفاوت و پیچیده به نظر برسد. اما نگران نباشید. این سینتکس را از این به بعد زیاد مشاهده خواهید کرد. استفاده از کلمه ی کلیدی new در تعریف تمام آبجکت ها کاربرد دارد. این روش تعریف توسط جاوا معرفی شد و در زبان ویژوال بیسیک و #C هم کاربرد وسیعی دارد. بنابراین بهتر است به آن عادت کنید.
مطابق معمول کلمه ی کلیدی Dim سپس نام لیست به صورت دلخواه، سپس نوع کلاس مورد نظر که در اینجا ArrayList می باشد، و سپس با استفاده از کلمه ی کلیدی new و constractor method کلاس مورد نظر یک نمونه آبجکت از این کلاس میسازیم. این قالب کلی است. در مورد کانسترکتور متود ها بعدا در دوره متوسطه هنگامی که راجع به شی گرایی صحبت کردیم، توضیح میدهیم. فعلا کار شما جز یادگیری ساختار این سینتکس و به خاطر سپردن آن نیست. همین الان چند لیست با نامهای دلخواه تعریف کنید و روی کاغذی بنویسید. مثلا :
Dim Ali As ArrayList = New ArrayList() Dim Reza As ArrayList = New ArrayList() Dim Whatever As ArrayList = New ArrayList()
و غیره
15-2-2 متدها و توابع ArrayList
برای نوشتن، خواندن و حذف داده ها درون لیست از متدهای آماده ی این کلاس استفاده میکنیم.
15-2-2-1 نوشتن داده درون لیست
برای این کار از متد ()Add استفاده میکنیم. فقط نام لیست خود را تایپ کرده و سپس یک نقطه جلوی آن بگذارید. ویژگی اینتلیسنس ویژوال استودیو، لیستی از متدهای آماده را نمایش میدهد. ما با متد ()Add کار داریم. اگر آن را یافتید، انتخابش کنید در غیر این صورت خیلی راحت آن را خودتان تایپ کنید. داده ای که میخواهید به لیست پاس دهید درون پرانتز ها بگذارید.
Dim myList As ArrayList = New ArrayList() myList.Add(“some data”)
این کار را به هر تعداد میتوانید انجام دهید.
15-2-2-2 خواندن داده از لیست
برای خواندن داده از لیست از ایندکس مربوطه به آن استفاده میکنیم. درست مانند آرایه ها معمولی ایندکس مورد نظر را درون پرانتز به نام لیست پاس داده و خروجی را در یک متغیر ذخیره کنید. دقت کنید که ایندکس از صفر شروع میشود. یعنی اولین داده درون لیست درست مانند آرایه ها ایندکس صفر دارد. دومین داده ایندکس یک، سومی ایندکس دو و به همین ترتیب تا آخر لیست.
Dim myList As ArrayList = New ArrayList() myList.Add(“Hello Students!”) myList.Add(“Visit topcoder.blog.ir”) Dim url As String url = myList(1)
در مثال بالا یک آرایه در خط اول تعریف کردیم، در خط دوم به آن یک مقدار پاس دادیم، در خط سوم یک مقدار دیگر هم به آن پاس دادیم، در خط چهارم یک متغیر معمولی از نوع رشته ای تعریف کردیم، در خط آخر مقدار داده ی دوم درون لیست را که ایندکس آن عدد یک است، به متغیر خود پاس دادیم.
15-2-2-3 حذف از لیست
برای حذف یک متغیر خاص از لیست از متد ()RemoveAt و ()Remove استفاده میکنیم. متد ()RemoveAt ایندکس داده را گرفته و آن را حذف میکند، در حالی که متد ()Remove خود مقدار داده را گرفته و آنرا حذف مینماید. توجه کنید که در هر دو روش بعد از حذف یک داده، کلیه داده های پس از آن یک ایندکس به عقب شیفت میابند. در ادامه ی مثال بالا میخواهیم داده ی اول را که رشته ی “!Hello Students” میباشد حذف کنیم. مثلا از متد ()RemoveAt استفاده میکنیم.
myList.RemoveAt(0)
پس از اجرای این دستور، داده ی اول حذف و داده ی دوم به جای آن مینشیند. یعنی اگر حالا دستور
url = myList(1)
را اجرا کنیم، با خطا مواجه میشویم. چرا که دیگر ایندکس 1 وجود ندارد و محتویات آن بعد از حذف داده ی اول لیست، به ایندکس صفر جهش کرده اند. برای درک این موضوع یک صف را تصور کنید که پنج نفر در آن هستند. وقتی نفر اول کار خود را انجام داده و صف را ترک میکند، نفر پشت سری او که نفر دوم بوده جایش را میگیرد و حالا نفر اول است. نفر سوم به نفر دوم تبدیل میشود و نفر چهارم جای نفر سوم را پر میکند. در لیست هم اگر از هر نقطه ای یک داده حذف کنید، تمام داده های بعد از آن یکی به عقب شیفت پیدا میکنند. این موضوع بعدها در برنامه نویسی مهم میشود. برای جلوگیری از خطاهای ناخواسته باید خوب این نکته را بیاموزید و به خاطر نگاه دارید.
15-2-2-4 برای خالی کردن تمام لیست
برای حذف تمام محتویات لیست از متد ()Clear استفاده میشود.
myList.Clear()
15-3 Dictionary
دیکشنری نوع دیگری از روش ذخیره سازی داده به صورت منظم و دینامیک میباشد که با روشهای دیگر ذخیره سازی داده یک تفاوت عمده دارد. داده ها در دیکشنری به صورت جفت ذخیره میشوند. به این صورت که یک کلید و یک مقدار در هر مورد ذخیره سازی باید تعیین گردد. برای دسترسی به هر مقدار باید از کلید مربوط به آن استفاده کرد. دیکشنری ها همچنین static type هستند. یعنی در هنگام تعیریف آنها باید نوع داده هایی که میخواهید در آنها ذخیره کنید مشخص بفرمایید و تا پایان کار این دیکشنری فقط از همان نوع داده میپذیرد. نوع داده ی کلید و مقدار میتوانند متفاوت باشند. دیکشنری ها به همین علت که نوع داده ی مشخص دارند، دارای متدهای مفید فراوان بوده و انواع عملیات در آنها قابل انجام است.
15-3-1 سینتکس Dictionary
سینتکس کلی دیکشنری ها به صورت زیر است:
Dim test As Dictionary(Of String, String) = New Dictionary(Of String, String)
ملاحظه میفرمایید که نوع داده ی دیکشنری بالا را در داخل پرانتز ها از نوع رشته ای قرار دادیم. انتخاب این نوع داده با شماست اما باید آن را در هنگام تعریف مشخص کرده و تا پایان از همان نوع داده در این دیکشنری ذخیره کنید.
15-3-2 متدها و توابع Dictionary ها
برای خواندن، نوشتن، و تغییر داده های درون دیکشنری از توابع و متدهای آماده ی این کلاس استفاده میکنیم.
15-3-2-1 نوشتن داده درون دیکشنری
برای این کار از متد ()Add استفاده میکنیم. این متد مانند متد مشابه برای لیست ها کار میکند با این تفاوت که دیکشنری دو ورودی برای هر داده میگیرد. کلید و مقدار. ورودی اول همیشه کلید و ورودی دوم همواره مقدار میباشد. به این سینتکس توجه فرمایید:
Dim author As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer) author.Add("Alireza", 24)
در کد بالا یک دیکشنری با نام author تعریف کرده و نوع داده ی کلید آن را از نوع رشته ای و نوع داده ی مقدار آن را از نوع عدد صحیح قرار دادیم. در خط بعدی هم با استفاده از متد ()Add کلید و مقدار مناسب مطابق با نوع داده هایی که در هنگام تعریف مشخص کرده بودیم در این دیکشنری ذخیره کردیم. حالا این دیکشنری یک عضو دارد. این عضو دارای یک کلید و یک مقدار است. اگر عضو دومی هم بخواهیم اضافه کنیم میتوانیم بنویسیم:
author.Add("Someone Else", 50)
حالا دیکشنری author دو عضو دارد. که هریک کلید و مقداری دارند. اولی کلید و دومی مقدار است.
15-3-2-2 خواندن داده از دیکشنری ها
برای خواندن داده از درون دیکشنری ها دو راه وجود دارد.
15-3-2-2-1 راه اول-پاس دادن کلید به دیکشنری و دریافت مقدار
در این روش همانند پاس دادن ایندکس ها به لیست ها یا آرایه ها و دسترسی به عضو منتصب به آن ایندکس فقط کافی است کلید را به دیکشنری پاس دهیم. نام دیکشنری را نوشته، و کلید را در داخل پرانتز مینویسیم. آنچه برمیگردد، مقدار مربوط به آن کلید خواهد بود:
Dim author As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer) author.Add("Alireza", 24) author.Add("Someone Else", 50) MessageBox.Show(author("Alireza"))
در بالا، عدد بیست و چهار در پنجره ی پیغام نمایش داده خواهد شد.
15-3-2-2-1 راه دوم-استفاده از متد item
همچنین میتوان کلید را به متد item پاس داد:
MessageBox.Show(author.Item("Alireza"))
این دو روش فرق چندانی ندارند و هر دو مقدار مربوط به کلید پاس داده شده را برمیگردانند.
15-3-2-3 جست و جو در دیکشنری
اگر کلیدی که به دیکشنری پاس میدهیم در این دیکشنری وجود نداشت چه اتفاقی می افتد؟ ممکن است بگویید خب با یک ارور هندلینگ مناسب میتوان از کرش کردن برنامه جلوگیری کرد. این درست اما برای ممانعت از کرش کردن برنامه در این حالت میتوان به روشی بهتر متوصل شد. میتوان قبل از پاس دادن کلید به دیکشنری، از وجود این کلید در دیکشنری اطمینان حاصل نمود. یعنی جست و جوی کلید در دیکشنری. جست و جو در دیکشنری نه تنها برای اطمینان از وجود یک کلید پیش از صدا زدن آن مناسب است، بلکه به شما امکان سرچ در میان داده هایتان را به صورت رانتایم میدهد.
برای اینکار از متد ()ContainsKey استفاده میکنیم. این متد یک مقدار بولین صحیح یا غلط برمیگرداند. اگر کلید را یافت، مقدار صحیح، وگرنه مقدار غلط برمیگرداند. این متد را در یک بلاک شرطی استفاده میکنیم:
Public Class Form2 Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim author As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer) author.Add("Alireza", 24) author.Add("Mehdi", 50) If author.ContainsKey("Alireza") Then MessageBox.Show("Alireza's Age is : " & author.Item("Alireza")) End If End Sub End Class
در قطعه کد بالا، پس از تعریف یک دیکشنری و انتصاب دو عضو برای آن، در رویداد فراخوانی فرم، در یک بلاک شرطی چک کردیم که آیا کلید مورد نظر در دیکشنری وجود دارد یا خیر. اگر وجود داشته باشد، یک پیغام چاپ میشود و مقدار متناسب با آن کلید را نمایش میدهد. اگر اینطور نباشد هیچ اتفاقی نمی افتد. کد بالا را میتوان با دانسته های قبلی خود کاملتر کرد:
Public Class Form2 Private author As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer) Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load author.Add("Alireza", 24) author.Add("Mehdi", 50) author.Add("Nasrin", 31) author.Add("Mina", 22) End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click If author.ContainsKey(TextBox1.Text) Then MessageBox.Show(TextBox1.Text & "'s Age is : " & author.Item(TextBox1.Text), "Match found", MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1) Else MessageBox.Show("No Match!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1) End If End Sub End Class
خروجی این کد را در شکل (15-1) مشاهده میکنید.
شکل 1-15تمرین: یک دیکشنری تعریف کنید که داده در رانتایم در خود ذخیره کند و بعد بتوان در آن جست و جو کرد و مقدار متناسب با کلید آن را نمایش داد. برای مثال یک دیکشنری که کلیدش نامهای دانشجوها و مقدارش معدل آنان باشد تعریف کنید.