اذهب إلى المحتوى

التعامل مع المصفوفات Arrays في لغة روبي


Hassan Hedr

المصفوفة array هي شكل من أشكال البيانات التي توفرها معظم لغات البرمجة والتي تسمح بتخزين عدة قيم تدعى عناصر معًا ضمن متغير واحد، ويمكن لهذه العناصر أن تكون من أنواع مختلفة من البيانات، مثل الأرقام والسلاسل النصية وغيرها من كائنات روبي. سنتعرف في هذا المقال على طرق إنشاء المصفوفات والوصول إلى القيم التي تحتويها، وإضافة وتعديل وحذف العناصر من المصفوفة، وطريقة المرور على عناصر المصفوفة، إذ تُعد المصفوفة في روبي كائنات مع توابعها الممكن استدعاؤها والاستفادة منها في التعامل مع عناصر المصفوفة.

إنشاء مصفوفة

في حال كان لدينا عدة قيم نحتاج التعامل معها ضمن البرنامج يمكننا تخزين كل منها في متغير خاص على النحو التالي:

shark1 = "Hammerhead"
shark2 = "Great White"
shark3 = "Tiger"

ولكن سنحتاج بتلك الطريقة لاختيار اسم متغير لكل قيمة منها، وفي حال كانت القيم كثيرة سيصبح الأمر صعبًا، وإذا أردنا إضافة قيمة جديدة إليها يجب تعريف متغير جديد وتذكُّر اسمه لاحقًا. هنا تأتي المصفوفات لحل تلك المشكلة عبر تخزين كل تلك القيم ضمن متغير واحد فقط. لإنشاء مصفوفة في روبي يمكن كتابة قيم العناصر ضمن أقواس معقوفة [] والفصل بينها بفواصل , على النحو التالي:

sharks = ["Hammerhead", "Great White", "Tiger"]

بدلًا من إنشاء ثلاثة متغيرات منفصلة أصبح لدينا الآن متغير واحد يحتوي على جميع القيم، ولإضافة قيمة جديدة للمصفوفة يمكن إضافتها مباشرةً دون الحاجة لإنشاء متغير جديد.

يمكن طباعة كامل المصفوفة باستخدام التابع print، الذي سيعرض محتويات المصفوفة كما يلي:

print sharks

ليكون الخرج على النحو التالي:

["Hammerhead", "Great White", "Tiger"]

توفر لغة روبي طريقةً مختصرةً لإنشاء مصفوفة يكون فيها كل مُدخل هو كلمة واحدة، وذلك بكتابة الكلمات بين القوسين في الصيغة التالية {}w% على النحو التالي:

days = %w{Monday Tuesday Wednesday Thursday Friday Saturday Sunday}

وسينتج عنها مصفوفة من الكلمات كما لو أننا عرفناها يدويًا ضمن أقواس معقوفة على النحو التالي:

days =  ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]

ونلاحظ عدم الحاجة لاستخدام علامات الاقتباس لتعريف تلك الكلمات ضمن الصيغة {}w%، ولسنا مضطرين لتخزين عناصر من نفس النوع ضمن المصفوفة، ففي روبي يمكن للمصفوفات أن تحتوي على أي نوع من القيم بما في ذلك مصفوفات أخرى، وفيما يلي مثال على مصفوفة تحتوي على سلسلة نصية والقيمة nil وعدد صحيح ومصفوفة من السلاسل النصية:

record = [
    "Sammy",
    null,
    7,
    [
        "another",
        "array",
    ]
]

سنتعرف في الفقرة التالية على كيفية الوصول إلى البيانات المخزنة ضمن المصفوفات.

الوصول لعناصر المصفوفة

للوصول إلى عنصر محدد ضمن المصفوفة يمكننا الإشارة إلى رقم الفهرس لذلك العنصر، أي ترتيب موقعه ضمن المصفوفة، إذ تبدأ الفهارس في روبي ومعظم لغات البرمجة الأخرى من الرقم صفر، فمثلًا للوصول إلى العنصر الأول من المصفوفة يمكننا تمرير رقم الفهرس له بعد اسم المتغير وبين الأقواس المعقوفة:

sharks = ["Hammerhead", "Great White", "Tiger"]

تحتوي المصفوفة sharks على ثلاثة عناصر، ورقم الفهرس لكل عنصر منها على النحو التالي:

2 1 0
Tiger Great White Hammerhead

العنصر الأول في المصفوفة وهو Hammerhead له الفهرس رقم 0، أما العنصر الأخير في المصفوفة وهو Tiger له الفهرس رقم 2، إذ وعلى عكس طريقة العد التقليدية التي تبدأ بالرقم 1، نلاحظ أن الفهارس تبدأ من الصفر، لذا يجب الاعتياد على ذلك عند التعامل مع المصفوفات لتجنب الأخطاء. يمكن معرفة عدد العناصر الموجودة في المصفوفة باستخدام التابع length على النحو التالي:

sharks.length

ليكون الخرج على النحو التالي:

3

على الرغم من أن فهارس المصفوفة sharks تبدأ من 0 وتنتهي بالفهرس 2، إلا أن تابع طول المصفوفة length يعيد عدد العناصر الموجودة في المصفوفة والذي يساوي 3، ولا علاقة له برقم الفهرس للعناصر.

ملاحظة: يمكنك التفكير في الفهرس على أنه إزاحة offset، أي عدد الأماكن من بداية المصفوفة، إذ يكون العنصر الأول في المقدمة وبالتالي بدون إزاحة، أي سيكون الفهرس 0، أما العنصر الثاني فهو على بُعد عنصر واحد من بداية المصفوفة، لذلك ستكون إزاحته بمقدار 1 وقيمة الفهرس 1.

لمعرفة رقم الفهرس لعنصر محدد ضمن المصفوفة مثل العنصرTiger يمكن استخدام التابع ()index على النحو التالي:

print sharks.index("Tiger")

ليعطي الخرج التالي:

2

يعيد هذا التابع رقم الفهرس لأول عنصر من المصفوفة يحتوي على النص المحدد، وإذا لم يُعثر على عنصر مطابق لتلك القيمة فسيعيد التابع القيمة nil:

print sharks.index("Whale")

سيكون هنا الخرج:

nil

للحصول على آخر عنصر من المصفوفة يمكن استخدام رقم الفهرس السالب 1-:

print sharks[-1]

وسيكون الخرج كما يلي:

"Tiger"

ويوجد أيضًا التابعين first و last في روبي للحصول على أول وآخر عنصر من المصفوفة دون الحاجة إلى استخدام رقم الفهرس لها:

puts sharks.first
puts sharks.last

ويكون الخرج:

"Hammerhead"
"Tiger"

وعند محاولة الوصول إلى فهرس غير موجود:

sharks[10]

سينتج عن ذلك القيمة nil:

nil

يمكن أن تحتوي المصفوفات على مصفوفات أخرى ضمنها لينتج من ذلك مصفوفات متداخلة nested arrays يمكن الاستفادة من هذا الشكل من البيانات لتمثيل البيانات ثنائية الأبعاد في البرنامج، ويمكنك الاطلاع على مزيدٍ من المعلومات عن المصفوفات وأنواعها من خلال المقال المصفوفات Arrays في روبي، وفيما يلي مثال على مصفوفة متداخلة:

nested_array = [
    [
        "salmon",
        "halibut",
    ],
    [
        "coral",
        "reef",
    ]
]

للوصول إلى العناصر الموجودة ضمن مصفوفة متداخلة يجب إضافة رقم فهرس إضافي يتوافق مع المصفوفة الداخلية، فمثلًا يمكن الوصول إلى القيمة coral من المصفوفة السابقة كما يلي:

print nested_array[1][0];

ليكون الخرج على النحو التالي:

coral

نستخرج في هذا المثال العنصر الثاني أولًا من المصفوفة عبر رقم الفهرس 1 من المتغير nested_array، وهو عنصر المصفوفة ["coral", "reef"]، ثم نستخرج العنصر الأول من هذه المصفوفة عبر رقم الفهرس 0 لنحصل بذلك على القيمة المطلوبة "coral".

سنتعرف في الفقرة التالية على طريقة إضافة عناصر إلى المصفوفة.

إضافة عناصر إلى المصفوفات

لنعود إلى المصفوفة السابقة sharks، التي تحتوي على ثلاثة عناصر تبدأ من رقم الفهرس 0 إلى 2:

sharks = ["Hammerhead", "Great White", "Tiger"]

لإضافة عنصر جديد إلى تلك المصفوفة، يمكن تعيين قيمة للفهرس الذي يلي آخر عنصر منها والذي في هذه الحالة هو 3 كما يلي:

sharks[3] = "Whale";

print sharks

ليكون الخرج على النحو التالي:

["Hammerhead", "Great White", "Tiger", "Whale"]

قد يؤدي استخدام هذه الطريقة إلى حدوث أخطاء، فإذا أضفنا عنصرًا إلى رقم فهرس ما أكبر من ذلك فسيؤدي ذلك لإضافة العنصر nil داخل المصفوفة على النحو التالي:

sharks[5] = "Sand";

print sharks;

ويكون الخرج في هذه الحالة:

["Hammerhead", "Great White", "Tiger", "Whale", nil, "Sand"]

وعند محاولة الوصول إلى قيمة ذلك العنصر الزائد سنحصل على القيمة nil:

sharks[4]

سيكون الخرج:

nil

يمكن استخدام التابع push لتجنب هذه الأخطاء، إذ يضيف هذا التابع عنصرًا إلى نهاية المصفوفة دون مشاكل:

sharks.push("Thresher")
print sharks

وعندها سيكون الخرج:

["Hammerhead", "Great White", "Tiger", "Whale", nil, "Whale", "Thresher"]

يمكن أيضًا استخدام الصيغة >> بدلًا من التابع push لإضافة عنصر إلى نهاية المصفوفة كما يلي:

sharks << "Bullhead"

ويكون الخرج:

["Hammerhead", "Great White", "Tiger", "Whale", nil, "Whale", "Thresher", "Bullhead"]

نستخدم التابع ()unshift لإضافة عنصر إلى بداية المصفوفة كما يلي:

sharks.unshift("Angel")
print sharks

ليعطي الخرج التالي:

["Angel", "Hammerhead", "Great White", "Tiger", "Whale", nil, "Whale", "Thresher", "Bullhead"]

سنتعرف في الفقرة التالية على طريقة إزالة عناصر من المصفوفة.

إزالة العناصر من المصفوفات

يمكن استخدام التابع delete أو delete_at لإزالة عنصر محدد من المصفوفة. لنختبر ذلك بإزالة العنصر الفارغ داخلها والذي أنشأناه عن طريق الخطأ، ونبدأ بالعثور على موضعه في المصفوفة باستخدام التابع index على النحو التالي:

print sharks.index(nil)

والذي يعطينا الخرج التالي:

4

ثم نستخدم التابع delete_at لإزالة ذلك صاحب الفهرس رقم 4 ونطبع المصفوفة لنتأكد:

sharks.delete_at(4)
print sharks

سيكون الخرج على النحو التالي:

["Angel", "Hammerhead", "Great White", "Tiger", "Whale", "Thresher", "Bullhead"]

يزيل التابع delete العناصر التي تتطابق مع القيمة التي تُمرّر له. لنختبر استخدامه بإزالة العنصر Whale من المصفوفة السابقة كما يلي:

sharks.delete("Whale")
print sharks;

ويكون الخرج في هذه الحالة:

["Angel", "Hammerhead", "Great White", "Tiger", "Thresher", "Bullhead"]

يزيل التابع delete جميع القيم المطابقة للقيمة التي نمررها له، لذا إذا كانت المصفوفة تحتوي على عناصر مكررة فستُزال جميعها، وبالمقابل يتيح التابع pop إزالة آخر عنصر من المصفوفة:

sharks.pop
print sharks;

ليكون الخرج كما يلي:

["Angel", "Hammerhead", "Great White", "Tiger", "Thresher"]

نلاحظ إزالة العنصر Bullhead، وهو آخر عنصر في المصفوفة. لإزالة أول عنصر من المصفوفة يمكن استخدام التابع shift على النحو التالي:

sharks.shift
print sharks

ليكون الخرج:

["Hammerhead", "Great White", "Tiger", "Thresher"]

نلاحظ إزالة العنصر Angel من بداية المصفوفة، ويمكن استخدام التابعين pop و shift لإزالة العناصر من بداية ونهاية المصفوفة كما لاحظنا، ويفضل استخدام التابع pop عند الحاجة لأن حذف العنصر من نهاية المصفوفة لن يؤثر على رقم الفهرس لباقي العناصر.

تعدل كلًا من التوابع delete_at و pop و shift على قيمة المصفوفة الأصلية وتعيد العنصر المحذوف:

sharks = ["Hammerhead", "Great White", "Tiger", "Whale"]
deleted_at_element = sharks.delete_at(1)
popped_element = sharks.pop

puts "Deleted_at element: #{deleted_at_element}"
puts "Popped element: #{popped_element}"

puts "Remaining array: #{sharks}"

وسيكون الخرج:

Deleted_at element: Great White
Popped element: Whale
Remaining array: ["Hammerhead", "Tiger"]

بعد أن تعرفنا على طرق إزالة العناصر من المصفوفة، سنتعرف في الفقرة التالية على طريقة التعديل على قيمة عنصر من المصفوفة.

تعديل عناصر موجودة في المصفوفات

يمكن تحديث قيمة عنصر من المصفوفة عن طريق تعيين قيمة جديدة لفهرس ذلك العنصر باستخدام معامل الإسناد تمامًا كما نُعرف المتغيرات العادية. تحتوي المصفوفة التالية على العنصر "Hammerhead" في الفهرس رقم 0، لنحاول تعديل قيمة ذلك العنصر إلى القيمة "Angel":

sharks = ["Hammerhead", "Great White", "Tiger", "Whale"]
sharks[0] = "Angel"
print sharks;

سيكون الخرج على النحو التالي:

["Angel", "Great White", "Tiger", "Whale"]

يمكن التأكد من تعديل قيمة ذلك العنصر بالبحث عن القيمة الجديدة باستخدام التابع index لنلاحظ أن القيمة الجديدة موجودة في نفس المكان. سنتعرف في الفقرة التالية على طريقة المرور على عناصر المصفوفة.

المرور على عناصر المصفوفة

توفر لغة روبي العديد من الطرق للمرور على عناصر المصفوفة، ويختلف التابع المُستخدم بحسب الهدف الذي نريده. لنبدأ بالمرور على عناصر المصفوفة وطباعة قيمة كل منها وذلك باستخدام الصيغةfor..in على النحو التالي:

sharks = ["Hammerhead", "Great White", "Tiger", "Whale"]
for shark in sharks do
  puts shark
end

تعيّن روبي قيمة كل عنصر في المتغير المحلي shark، ويمكنك بعد ذلك طباعة قيمة ذلك العنصر باستخدام التابع puts. على الرغم من إمكانية استخدام الحلقة التكرارية for..in للمرور على عناصر المصفوفة، إلا أن المصفوفات في لغة روبي هي كائنات ويتوفر ضمنها التابع each، الذي يعمل بنفس طريقة الحلقة التكرارية for..in ولكن بصيغة مختلفة:

sharks = ["Hammerhead", "Great White", "Tiger", "Whale"]
sharks.each do |shark|
  puts shark
end

يستخدم التابع each صيغةً تتكرر كثيرًا في لغة روبي، إذ يأخذ التابع كتلة block مثل وسيط، ويُقصد بالكتلة هنا شيفرة برمجية ستنفذ لاحقًا في سياق التابع. ستُنفذ في مثالنا السابق العبارة البرمجية puts shark، أما الكلمة shark المحاطة بعلامات الأنبوب | هي المتغير المحلي الذي يمثل العنصر الحالي في المصفوفة، إذ تسنِد لغة روبي قيمة العنصر الحالي إلى هذا المتغير وتنفذ بعدها التعبير الموجود ضمن الكتلة، ويكرّر التابع each هذه العملية لكل عنصر من عناصر المصفوفة، ويكون الخرج على النحو التالي:

Hammerhead
Great White
Tiger
Whale

يمكن استخدام الصيغة المختصرة ضمن الأقواس المعقوصة curly braces {} بدلًا من كلمتي do و end إذا كانت الكتلة مكونةً من سطر برمجي واحد فقط:

...
sharks.each {|shark| puts shark }

وسينتج عنها نفس الخرج السابق.

يعمل التابع each_with_index بنفس طريقة التابع each، ولكنه يتيح الوصول إلى رقم الفهرس للعنصر الحالي في المصفوفة. لنختبر ذلك بطباعة رقم الفهرس والقيمة لكل عنصر من المصفوفة:

sharks = ["Hammerhead", "Great White", "Tiger", "Whale"]
sharks.each_with_index do |shark, index|
  puts "The index is #{index}"
  puts "The value is #{shark}"
end

تسند روبي قيمة كل عنصر في المصفوفة إلى المتغير shark، وتسند رقم الفهرس الحالي إلى المتغير index في كل مرة، ويمكن بعد ذلك الإشارة إلى هذين المتغيرين داخل الكتلة بحيث يمكن الوصول إلى قيمة العنصر الحالي ورقم فهرسه في المصفوفة.

The index is 0
The value is Hammerhead
The index is 1
The value is Great White
The index is 2
The value is Tiger
The index is 3
The value is Whale

تعلمنا في هذه الفقرة عدة طرق للمرور على عناصر المصفوفة، وهي من أكثر المهمات التي نحتاجها عند التعامل مع المصفوفات.

الخاتمة

المصفوفات في روبي ومعظم لغات البرمجة من المفاهيم المهمة والقوية والتي يجب التعرف عليها وطرق التعامل معها. تعرّفنا في هذا المقال على المصفوفات وكل المهمات الأساسية للتعامل معها من إنشاء المصفوفات والوصول إلى عناصرها وإضافة وإزالة وتعديل العناصر ضمن المصفوفة، وتعرفنا على طريقتين للمرور على عناصر المصفوفة وعرض محتوياتها.

لمزيد من التفصيل، ارجع إلى صفحة النوع Array في موسوعة حسوب.

ترجمة -وبتصرف- للمقال How To Work with Arrays in Ruby لصاحبيه Brian Hogan و Tony Tran.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...