آرایه های چند بعدی

آرایه‌های چند بعدی، آرایه‌هایی هستند که برای دسترسی به هر یک از عناصر آنها باید از چندین اندیس استفاده کنیم. یک آرایه چند بعدی را می‌توان مانند یک جدول با تعدای ستون و ردیف تصور کنید. با افزایش اندیسها اندازه ابعاد آرایه نیز افزایش می‌یابد و آرایه‌های چند بعدی با بیش از دو اندیس به وجود می‌آیند. نحوه ایجاد یک آرایه با دو بعد به صورت زیر است :

val arrayName = Array(row, {typeArray(column)})

Array یک کلاس است که سازنده آن دو پارامتر می‌گیرد. یکی تعداد آرایه‌ها (row) و دیگری نوع آرایه که به وسیله کلاس‌هایی که در درس قبل ذکر شد (مانند IntArray) به همراه تعداد عناصر آن (column). کد بالا را به صورت زیر هم می‌توان نوشت:

val arrayName = Array(row) {typeArray(column)}

می‌توان یک آرایه با تعداد زیادی بعد ایجاد کرد به شرطی که هر بعد دارای طول مشخصی باشد. در یک آرایه دو بعدی برای دسترسی به هر یک از عناصر به دو مقدار نیاز داریم یکی مقدار X و دیگری مقدار Y که مقدار x نشان دهنده ردیف و مقدار Y نشان دهنده ستون آرایه است البته اگر ما آرایه دو بعدی را به صورت جدول در نظر بگیریم. در شکل زیر مکان هر عنصر در یک آرایه دو بعدی نشان داده شده است.

مقدار 3 را به x اختصاص می‌دهیم چون 3 سطر یا آرایه داریم و مقدار 5 را به Y چون هر آرایه 5 ستون دارد، اختصاص می‌دهیم. چطور یک آرایه چند بعدی را مقدار دهی کنیم؟ در این حالت که از کلاس Array استفاده کرده‌ایم باید مقدار دهی به عناصر را به صورت دستی انجام داد مانند :

val numbers = Array(3, {IntArray(5)})

numbers[0][0] = 1
numbers[0][1] = 2
numbers[0][2] = 3
numbers[0][3] = 4
numbers[0][4] = 5
numbers[1][0] = 6
numbers[1][1] = 7
numbers[1][2] = 8
numbers[1][3] = 9
numbers[1][4] = 10
numbers[2][0] = 11
numbers[2][1] = 12
numbers[2][2] = 13
numbers[2][3] = 14
numbers[2][4] = 15

همانطور که مشاهده می‌کنید برای دسترسی به هر یک از عناصر در یک آرایه دو بعدی به سادگی می‌توان از اندیسهای X و Y و یک جفت کروشه مانند مثال استفاده کرد. یک راه دیگر برای تعریف یک آرایه دو بعدی استفاده از تابع ()arrayOf است. به عنوان مثال :

val numbers = arrayOf(
                        intArrayOf( 1,  2,  3,  4,  5),
                        intArrayOf( 6,  7,  8,  9, 10),
                        intArrayOf(11, 12, 13, 14, 15)
                     )

این تابع آرایه‌ای از آرایه‌ها را دریافت می‌کند. ما در کد بالا یک آرایه به نام number تعریف کرده‌ایم که سه آرایه از نوع اعداد صحیح در خود جای داده است و هر آرایه هم 5 عنصر یا ستون دارد. یعنی آرایه number دارای 3 سطر و 5 ستون است.

گردش در میان عناصر آرایه‌های چند بعدی

گردش در میان عناصر آرایه‌های چند بعدی نیاز به کمی دقت دارد. یکی از راههای آسان استفاده از حلقه for تو در تو است:

  1: fun main(args: Array<String>)
  2: {
  3:     val numbers = arrayOf(
  4:                              intArrayOf(1, 2, 3, 4, 5),
  5:                              intArrayOf(6, 7, 8, 9, 10),
  6:                              intArrayOf(11, 12, 13, 14, 15)
  7:                           )
  8: 
  9:     for (number in numbers)
 10:     {
 11:         for (num in number)
 12:         {
 13:             print(num.toString() + " ")
 14:         }
 15:     }
 16: }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

مشاهده کردید که گردش در میان مقادیر عناصر یک آرایه چند بعدی چقدر راحت است. در برنامه بالا از یک حلقه برای گردش در میان آرایه‌ها و از حلقه دیگر برای گردش در میان عناصر آنها استفاده کرده‌ایم. ولی این کد ناقص است و تمام مقادیر را در یک خط چاپ می‌کند. اگر بخواهیم مقادیر مربوط به هر آرایه را در یک خط چاپ کنیم باید چکار کنیم؟ به برنامه زیر توجه کنید:

  1: fun main(args: Array<String>)
  2: {
  3:     val numbers = arrayOf(
  4:             intArrayOf(1, 2, 3, 4, 5),
  5:             intArrayOf(6, 7, 8, 9, 10),
  6:             intArrayOf(11, 12, 13, 14, 15)
  7:     )
  8: 
  9:     for (row in numbers.indices)
 10:     {
 11:         for (col in 0 until numbers[row].size)
 12:         {
 13:             print(numbers[row][col].toString() + " ")
 14:         }
 15: 
 16:         //Go to the next line
 17:         println()
 18:     }
 19: }
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15

همانطور که در مثال بالا نشان داده شده است با استفاده از یک حلقه ساده for نمی‌توان به مقادیر دسترسی یافت بلکه به یک حلقه for تو در تو نیاز داریم. به زبان ساده در کد بالا دو حلقه for داریم. یکی برای به دست آوردن تعداد آرایه‌ها و دیگری برای به دست آوردن ستون یا تعداد عناصر آرایه‌ها. در اولین حلقه for، با استفاده از خاصیت indices، اندیس آرایه‌های موجود در آرایه numbers که در اصل همان تعداد آرایه‌ها می‌باشد را به دست می‌آوریم. این خط را می‌توان به صورت زیر هم نوشت :

for(row in 0..2)

چرا 2..0؟ چون اندیس آرایه‌ها هم از صفر شروع می‌شود. یعنی اندیس اولین آرایه دارای اندیس 0 و … . در حلقه for دوم با استفاده از خاصیت size، تعداد ستون‌های یک آرایه را به دست می‌آوریم. و چون تعداد عناص یا ستون‌های همه آرایه‌ها برابر 5 است پس عبارت numbers[row].size عدد 5 را بر می‌گرداند. در نتیجه خط 11 را می‌توان به صورت زیر هم نوشت :

for (col in 0 until 5)

در مجموع می‌توان گفت که row اعداد 0، 1 و 2 را در خود جای می‌دهد و column هم اعداد 0، 1، 2، 3 و 4. در نتیجه وقتی که مقدار ردیف (row) 0 باشد، حلقه دوم از [0][0] تا [4][0] اجرا شود. سپس مقدار هر عنصر از آرایه را با استفاده از حلقه نشان می‌دهیم، اگر مقدار ردیف (row) برابر 0 و مقدار ستون (col) برابر 0 باشد مقدار عنصری که در ستون 1 و ردیف 1 (numbers[0][0]) قرار دارد نشان داده خواهد شد که در مثال بالا عدد 1 است.

بعد از اینکه دومین حلقه تکرار به پایان رسید، فوراً دستورات بعد از آن اجرا خواهند شد، که در اینجا دستور println() که به برنامه اطلاع می‌دهد که به خط بعد برود (خط 17). سپس حلقه با اضافه کردن یک واحد به مقدار row این فرایند را دوباره تکرار می‌کند. سپس دومین حلقه for اجرا شده و مقادیر دومین ردیف نمایش داده می‌شود. حال بیایید آنچه را از قبل یاد گرفته‌ایم در یک برنامه به کار بریم. این برنامه نمره چهار درس مربوط به سه دانش آموز را از ما می‌گیرد و معدل سه دانش آموز را حساب می‌کند.

  1: fun main(args: Array<String>)
  2: {
  3:     val studentGrades = Array(3) { DoubleArray(4) }
  4:     var total: Double
  5: 
  6:     for (student in studentGrades.indices)
  7:     {
  8:         total = 0.0
  9: 
 10:         println("Enter grades for Student ${student + 1}")
 11: 
 12:         for (grade in 0 until studentGrades[student].size)
 13:         {
 14:             print("Enter Grade #${grade + 1}: ")
 15:             studentGrades[student][grade] = readLine() !!.toDouble()
 16:             total += studentGrades[student][grade]
 17:         }
 18: 
 19:         print("Average is ${total / studentGrades[student].size}")
 20:         println()
 21:     }
 22: }
Enter grades for Student 1
Enter Grade #1: 92
Enter Grade #2: 87
Enter Grade #3: 89
Enter Grade #4: 95
Average is 90.75

Enter grades for Student 2
Enter Grade #1: 85
Enter Grade #2: 85
Enter Grade #3: 86
Enter Grade #4: 87
Average is 85.75

Enter grades for Student 3
Enter Grade #1: 90
Enter Grade #2: 90
Enter Grade #3: 90
Enter Grade #4: 90
Average is 90.00

در برنامه بالا یک آرایه چند بعدی از نوع Double تعریف شده است (خط 3). این آرایه 3 آرایه دارد و هر آرایه 4 عنصر. در کل 3 دانش آموز و هر دانش آموز 4 درس. همچنین یک متغیر به نام total تعریف می‌کنیم که مقدار محاسبه شده معدل هر دانش آموز را در آن قرار دهیم (خط 4). حال وارد حلقه for تو در تو می‌شویم (خط 6). در اولین حلقه for تعداد دانش آموزان را با استفاده از خاصیت indices به دست می‌آوریم. در نتیجه متغیر student اعداد 0، 1 و 2 را در خود ذخیره می‌کند. وارد بدنه حلقه for می‌شویم. در خط 8 مقدار متغیر total را برابر صفر قرار می‌دهیم. بعداً مشاهده می‌کنید که چرا این کار را انجام دادیم. سپس برنامه یک پیغام را نشان می‌دهد و از شما می‌خواهد که شماره دانش آموز را وارد کنید (student + 1). عدد 1 را به student اضافه کرده‌ایم تا به جای نمایش student 0، با student 1 شروع شود، تا طبیعی‌تر به نظر برسد. سپس به دومین حلقه for در خط 12 می‌رسیم. در این حلقه یک متغیر شمارنده به نام grade تعریف می‌کنیم و تعداد عناصر آرایه را با استفاده از studentGrades[student].size را در آن قرار می‌دهیم. این متغیر اعداد 0، 1، 2 و 3 را در خود جای می‌دهد. برنامه چهار نمره مربوط به دانش آموز را می‌گیرد. هر وقت که برنامه یک نمره را از کاربر دریافت می‌کند، نمره به متغیر total اضافه می‌شود.

وقتی همه نمره‌ها وارد شدند، متغیر total هم جمع همه نمرات را نشان می‌دهد. در خط 19 معدل دانش آموز نشان داده می‌شود. معدل از تقسیم کردن total (جمع) بر تعداد نمرات به دست می‌آید.