الصنف Array في روبي

من موسوعة حسوب

المصفوفات هي مجموعات مُرتَّبة ومُفهرسة بالأعداد الصحيحة (integer-indexed) ومُكونة من أي نوع من الكائنات.

تبدأ فهارس المصفوفات بالعدد 0، كما هو الحال في لغتي C و Java. ويفترض أن يُحسب الفهرس السالب بدءًا من نهاية المصفوفة، أي أنَّ الفهرس ذا القيمة ‎-1 يشير إلى العنصر الأخير في المصفوفة، والفهرس ‎-2 يمثل موضع العنصر ما قبل الأخير، وهلم جرًا.

إنشاء المصفوفات

يمكن إنشاء مصفوفة جديدة باستخدام المعامل [] الباني.

يمكن أن تحتوي المصفوفة نفسها على أنواع مختلفة من الكائنات. على سبيل المثال، المصفوفة التالية تحتوي على عدد صحيح (Integer) وسلسلة نصية (String) وعدد عشري:

ary = [1, "two", 3.0] #=> [1, "two", 3.0]

كما يمكن إنشاء مصفوفة من خلال استدعاء التابع ‎ ::newمباشرةً دون تمرير أية وسائط إليه، أو مع تمرير وسيط واحد (الذي يمثل الحجم الأولي للمصفوفة) أو وسيطين (الحجم الأولي والكائنات الافتراضية [default object]).

ary = Array.new    #=> []
Array.new(3)       #=> [nil, nil, nil]
Array.new(3, true) #=> [true, true, true]

لاحظ أنَّ الوسيط الثاني يملأ كامل المصفوفة بقيمة الكائن المعطى نفسه. بناءً على ذلك، يُنصح باستخدامه فقط في الحالات التي تحتاج فيها إلى إنشاء مصفوفات باستخدام كائنات غير قابلة للتغيير (immutable) مثل الرموز (Symbols) والأرقام والقيم المنطقية. لإنشاء مصفوفة تحتوي كائنات مختلفة، فيمكن تمرير كتلة برمجية إلى التابع new‎. هذه الطريقة آمنة للاستخدام مع الكائنات القابلة للتغيير (mutable) مثل الخرائط (hashes) أو السلاسل النصية (strings) أو مصفوفات أخرى:

Array.new(4) { Hash.new }  #=> [{}, {}, {}, {}]
Array.new(4) {|i| i.to_s } #=> ["0", "1", "2", "3"]

هذه الطريقة مفيدة وسريعة لبناء مصفوفات متعددة الأبعاد (multi-dimensional arrays):

Array.new(4) { Hash.new }  #=> [{}, {}, {}, {}]
Array.new(4) {|i| i.to_s } #=> ["0", "1", "2", "3"]

يمكن أيضًا إنشاء مصفوفة باستخدام التابع Array()‎، والذي يستدعي التابع to_ary ثم التابع to_a مع الوسائط المُمرَّرة.

Array({:a => "a", :b => "b"}) #=> [[:a, "a"], [:b, "b"]]

التوابع المستعملة مع المصفوفات

بالإضافة إلى توابع الصنف Enumerable، فإنّ للصنف Array توابع خاصة به تستعمل في الوصول إلى المصفوفة والبحث فيها وغيرها من الأمور.

الوصول إلى العناصر

يمكن جلب عناصر من أي مصفوفة باستخدام معامل الفهرسة ‎[]‎، إذ يمرَّر إلى هذا المعامل عددًا صحيحًا واحدًا (يمثل فهرس العنصر [index])، أو زوجًا من الأعداد (أحدهما يمثل بداية العنصر والأخر يمثل طول العناصر المراد جلبها)، أو مجالًا (يمثل بداية ونهاية العناصر المراد جلبها). إن أعطيت قيمة سالبة للفهرس، فسيُسحَب موضع العنصر بدءًا من نهاية المصفوفة؛ يمثل الفهرس ‎-1 مثلًا موضع العنصر الأخير.

arr = [1, 2, 3, 4, 5, 6]
arr[2]    #=> 3
arr[100]  #=> nil
arr[-3]   #=> 4
arr[2, 3] #=> [3, 4, 5]
arr[1..4] #=> [2, 3, 4, 5]
arr[1..-3] #=> [2, 3, 4]

هنالك طريقة أخرى للوصول إلى أحد عناصر مصفوفة وهي باستخدام التابع at:

arr.at(0) #=> 1

أمَّا التابع slice، فيعمل بطريقة مشابهة لمعامل الفهرسة ‎[]‎. إن أردت أن يُطلَق خطأٌ أو تُظهر رسالة أو قيمة معينة إذا أشار فهرسٌ إلى عنصر خارج المصفوفة، فيمكنك استخدام التابع fetch.

arr = ['a', 'b', 'c', 'd', 'e', 'f']
arr.fetch(100) #=> IndexError: index 100 outside of array bounds: -6...6
arr.fetch(100, "oops") #=> "oops"

يجلب التابعان first و last العنصرين الأول والأخير من مصفوفة على التوالي.

arr.first #=> 1
arr.last  #=> 6

للحصول على أول n عنصر من مصفوفة، يمكن استخدام التابع take:

arr.take(3) #=> [1, 2, 3]

يفعل التابع drop بشكل معاكس لما يفعله التابع take، إذ يعيد آخر n عنصر من المصفوفة:

arr.drop(3) #=> [4, 5, 6]

الحصول على معلومات متعلقة بمصفوفة

تخزِّن المصفوفات طولها (عدد عناصرها [تدعى «حجم المصفوفة» في بعض الأحيان]) باستمرار. لمعرفة عدد عناصر أي مصفوفة، يمكن استخدام أحد التوابع length أو count أو size:

browsers = ['Chrome', 'Firefox', 'Safari', 'Opera', 'IE']
browsers.length #=> 5
browsers.count #=> 5

للتحقق مما إذا كانت مصفوفة فارغة أم لا، يمكن استخدام التابع empty?‎:

browsers.empty? #=> false

لمعرفة إذا كان عنصر معين موجودًا في مصفوفة، يمكن استخدام التابع include?‎:

browsers.include?('Konqueror') #=> false

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

يمكن إضافة عناصر معينة إلى نهاية مصفوفة باستخدام إمَّا التابع push أو المعامل ‎‎<<‎:

arr = [1, 2, 3, 4]
arr.push(5) #=> [1, 2, 3, 4, 5]
arr << 6    #=> [1, 2, 3, 4, 5, 6]

أمَّا التابع unshift، فيضيف عنصرًا جديدًا إلى بداية المصفوفة.

arr.unshift(0) #=> [0, 1, 2, 3, 4, 5, 6]

يستعمل التابع insert لإدراج عنصر جديد في المصفوفة في أي موضع فيها.

arr.insert(3, 'apple')  #=> [0, 1, 2, 'apple', 3, 4, 5, 6]

ويستعمل التابع insert أيضًا لإدراج عدة قيم في الوقت نفسه:

arr.insert(3, 'orange', 'pear', 'grapefruit')
#=> [0, 1, 2, "orange", "pear", "grapefruit", "apple", 3, 4, 5, 6]

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

يزيل التابع pop العنصر الأخير من مصفوفة ثم يعيده:

arr =  [1, 2, 3, 4, 5, 6]
arr.pop #=> 6
arr #=> [1, 2, 3, 4, 5]

لجلب العنصر الأول من مصفوفة وحذفه أيضًا منها في الوقت نفسه، استخدم التابع shift:

arr.shift #=> 1
arr #=> [2, 3, 4, 5]

لحذف عنصر ذي فهرس محدد، يمكن استعمال التابع delete_at:

arr.delete_at(2) #=> 4
arr #=> [2, 3, 5]

لحذف عنصر معين موجود في أي مكان في مصفوفة، يمكن استخدام التابع delete:

arr = [1, 2, 2, 3]
arr.delete(2) #=> 2
arr #=> [1,3]

إن أردت إزالة كل القيم nil من مصفوفة، فاستخدم التابع compact :

arr = ['foo', 0, nil, 'bar', 7, 'baz', nil]
arr.compact  #=> ['foo', 0, 'bar', 7, 'baz']
arr          #=> ['foo', 0, nil, 'bar', 7, 'baz', nil]
arr.compact! #=> ['foo', 0, 'bar', 7, 'baz']
arr          #=> ['foo', 0, 'bar', 7, 'baz']

لإزالة العناصر المتكررة من مصفوفة، يمكن استخدام إمَّا التابع uniqالذي لا يغير المصفوفة (non-destructive) أو التابع uniq!‎ الذي يغير المصفوفة (destructive).

arr = [2, 5, 6, 556, 6, 6, 8, 9, 0, 123, 556]
arr.uniq #=> [2, 5, 6, 556, 8, 9, 0, 123]

تنفيذ عمليات تكرارية على المصفوفات

بشكل مشابه لكل الأصناف التي تشملها الوحدة Enumerable، يملك الصنف Array التابع each الذي يحدد العناصر التي يراد التكرار عليها وما الذي سيطبق في كل عملية. في حالة التابع each الخاص بالصنف Array، كل عناصر المصفوفة تكون مشمولةً في تكرار تنفيذ كتل برمجية معطاة عليها.

لاحظ أنَّ هذه العملية لا تغير المصفوفة:

arr = [1, 2, 3, 4, 5]
arr.each { |a| print a -= 10, " " }
# prints: -9 -8 -7 -6 -5
#=> [1, 2, 3, 4, 5]

من التوابع المفيدة أيضًا التابع reverse_each، الذي يشبه التابع each تمامًا باستثناء أنه يكرّر (iterate) تنفيذ الكتلة البرمجية على عناصر المصفوفة بشكل معاكس أي يبدأ من العنصر الأخير وحتى العنصر الأول.

words = %w[first second third fourth fifth sixth]
str = ""
words.reverse_each { |word| str += "#{word} " }
p str #=> "sixth fifth fourth third second first "

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

arr.map { |a| 2*a }   #=> [2, 4, 6, 8, 10]
arr                   #=> [1, 2, 3, 4, 5]
arr.map! { |a| a**2 } #=> [1, 4, 9, 16, 25]
arr                   #=> [1, 4, 9, 16, 25]

اختيار عناصر محددة من مصفوفة

يمكن اختيار عناصر من مصفوفة وفقًا لمعايير محددة في كتلة برمجية (block). يمكن أن تجرى عملية الاختيار بطريقة هادمة (destructive) للمصفوفة الأصلية أو بطريقة غير هادمة (non-destructive)، إذ ستعدل العمليات الهادمة على المصفوفة الأصلية بينما تنشئ العمليات غير الهادمة مصفوفة جديدة تضع فيها العناصر الناتجة.

الاختيار غير الهادم (Non-destructive Selection)

مثالٌ على الاختيار غير الهادم الذي يجرى باستعمال التابع select، والتابع reject، والتابع drop_while:

arr = [1, 2, 3, 4, 5, 6]
arr.select { |a| a > 3 }     #=> [4, 5, 6]
arr.reject { |a| a < 3 }     #=> [3, 4, 5, 6]
arr.drop_while { |a| a < 4 } #=> [4, 5, 6]
arr                          #=> [1, 2, 3, 4, 5, 6]

الاختيار الهادم (Destructive Selection)

يقابل التابعان select!‎ و reject!‎ الهادمان التابعين select و reject غير الهادمين.

بشكل مماثل للتابع select والتابع reject المعاكس له، يعطي التابعان delete_if و keep_if نتيجة معاكسة إن استعملت معهما الكتلة البرمجية نفسها:

arr.delete_if { |a| a < 4 } #=> [4, 5, 6]
arr                         #=> [4, 5, 6]

arr = [1, 2, 3, 4, 5, 6]
arr.keep_if { |a| a < 4 } #=> [1, 2, 3]
arr                       #=> [1, 2, 3]

توابع الصنف العامة (Public Class Methods)

new

تنشئ الدالة new‎‎ مصفوفةً جديدةً.

[]

يعيّن قيمة عنصر ذي فهرس محدد،

Array

ينشئ مصفوفةً جديدةً تحوي الكائنات المُمرّرة إليها.

-

يعيد المعامل - مصفوفة جديدة تمثل نسخة من جميع عناصر المصفوفة الأصلية باستثناء العناصر المشتركة مع المصفوفة الأخرى. ت

try_convert

يحوّل كائنًا إلى مصفوفة بالاستعانة بالتابع to_ary.

توابع النسخة العامة (Public Instance Methods)

&

يعيد المعامل & مصفوفةً جديدةً تحتوي على العناصر المشتركة بين مصفوفتين دون تكرارها.

star

إن استعمل المعامل * مع مصفوفة وسلسلة نصية، فسيُكافئ حينئذٍ العبارة ary.join(str).

plus

يجمع المعامل + مصفوفتين معًا في مصفوفة واحدة جديدة.

>>

يضيف المعامل >> كائنًا مُحدَّدًا إلى نهاية المصفوفة الأصلية ثم يعيد المصفوفة نفسها، لذا يمكن تكرار هذا المعامل عدة مرات وبشكل متسلسل.

<=>

يعيد معامل الموازنة <=> عددً‎ا صحيحًا (‎-1 أو 0 أو ‎+1) إذا كانت المصفوفة الأصلية أصغر من أو تساوي أو أكبر من المصفوفة الأخرى المعطاة على التوالي. يوازن كل كائن من كل مصفوفة باستخدام المعامل <=>.

==

يتحقق المعامل == من تساوي مصفوفتين مع بعضهما بعضًا.

any?‎

يتحقق إذا كان كل عنصر من عناصر المصفوفة المعطاة محققًا لشرط منطقي محدد أو كانت قيمة كل عنصر لا تساوي القيمة false.

>>

يضيف المعامل >> كائنًا مُحدَّدًا إلى نهاية المصفوفة الأصلية ثم يعيد المصفوفة نفسها، لذا يمكن تكرار هذا المعامل عدة مرات وبشكل متسلسل.

assoc

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

at

يجلب عنصرًا ذي فهرس محدد من المصفوفة المستدعاة معه.

bsearch

يبحث باستخدام البحث الثنائي (binary search) عن قيمة من مصفوفة تحقق شرطًا منطقيًّا محددًا ويستغرق ‎O(log n)‎، إذ n حجم المصفوفة.

bsearch_index

يبحث  باستخدام البحث الثنائي (binary search) عن فهرسٍ لعنصر من مصفوفة يحقق شرطًا منطقيًّا محددًا ويستغرق ‎O(log n)‎، إذ n هي حجم المصفوفة.

clear

يزيل كل عناصر المصفوفة.

collect

يستدعي  كتلة برمجية محدَّدة مع كل عنصر من عناصر مصفوفة ثمَّ يعيد مصفوفة جديدة تحوي القيم التي تعيدها تلك الكتلة.

!collect

يستدعي  كتلة برمجية محددة مع كل عنصر من عناصر مصفوفة ثم يضع القيمة التي أعادتها تلك الكتلة مكان العنصر الذي استدعيت معه.

combination

يجمِّععناصر المصفوفة المعطاة مع بعضها بعضًا في مصفوفات بطول يساوي القيمة n الممررة إليه ثم يضع هذه المصفوفات في المصفوفة نفسها المعطاة ويعيدها. لا يوجد أي ضمان للتنبؤ بترتيب العناصر المجمَّعة المعادة.

compact

يعيد نسخةً جديدة من المصفوفة التي استُدعي معها مع حذف كل العناصر التي تساوي nil منها.

compact!‎

يحذف كل العناصر ذات القيمة nil من المصفوفة التي استدعيت معه ثم يعيدها. إن لم تحوي المصفوفة أي عنصر يساوي nil، فسيعيد التابع compact!‎ القيمة nil.

concat

يضيف جميع عناصر المصفوفات المُمرّرة إليه إلى المصفوفة التي استُدعيت معه.

count

يعيد  عدد عناصر المصفوفة التي استُدعيت معه أو عدد العناصر المتساوية مع قيمة معينة (يتحقق من ذلك باستعمال المعامل ==) أو عدد العناصر التي تحقق شرطًا محددًا.

cycle

يستدعي  كتلة برمجية محددة مع كل عنصر من عناصر المصفوفة عددًا محددًا من المرات أو عددًا لا نهائيًّا من المرات إن أعطيت القيمة nil. أمَّا إن مُرِّرت إليه قيمة سالبة أو كانت المصفوفة فارغة، فلن يفعل هذا التابع أي شيء. يعيد التابع القيمة nil إن انتهت سلسلة الاستدعاءات المطبقة على كل عنصر دون مقاطعة.إن لم تمرَّر أي كتلة، فسيعيد التابع cycle كائنا من النوع Enumerator.

delete

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

delete_at

يحذف  عنصرًا ذا فهرس محدَّد من مصفوفة.

delete_if

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

dig

يستخرج  العنصر المتشعِّب (nested value) المحدَّد بسلسلة المعاملات الممرَّرة إليه من مصفوفة متعددة الأبعاد وذلك عبر استدعاء dig عند كل مستوى تشعب.

drop

يحذف التابع drop أول n عنصر من مصفوفة ثمَّ يضع بقية العناصر في مصفوفة جديدة ويعيدها.

drop_while

يحذف التابع drop_while عناصر المصفوفة الأولى التي تحقِّق شرطًا محدَّدًا ثمَّ يعيد مصفوفة جديدة تحوي بقية العناصر.

each

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

 eql?‎

يتحقق من أن مصفوفتين تتضمنان نفس العناصر، وذلك بحسب التابع Object.eql?‎.

each_index

يستدعي  كتلة برمجية محددة مع فهرس كل عنصر من عناصر مصفوفة، إذ يُمرَّر ذلك الفهرس كوسيط إلى الكتلة ثم يعيد المصفوفة نفسها.

empty?‎‎

يتحقق  إن كانت مصفوفةٌ فارغةً أم لا.

fetch

يجلب عنصرًا ذا فهرس محدَّد من مصفوفة. إن كان الفهرس المعطى لعنصرٍ يقع خارج نطاق المصفوفة، فسيُطلَق الخطأ IndexError.

fill

يضبط قيم عناصر محدَّدة أو جميع عناصر مصفوفة إلى القيمة الممرَّرة إليه (الأشكال الثلاث الأولى للتابع في قسم «البنية العامة»)، أو القيم التي تعيدها الكتلة البرمجية الممرَّرة إليه (الأشكال الثلاث المتبقية).

find_index

يجلب  فهرس أول ظهور لعنصر محدَّد من مصفوفة أو فهرس أول عنصر يحقق شرطًا محدَّدًا.

first

يجلب أول عنصر أو أول n عنصر من مصفوفة.

flatten

يجعل  المصفوفة التي تحوي عناصر متشعبة ضمنها مصفوفةً أحادية البعد بشكل تعاودي (recursively)؛ أي أنَّ كل عنصر من عناصر المصفوفة المعطاة والذي قد يكون نفسه مصفوفةً متشعبةً من مستوًى واحدٍ أو أكثر ستُستخلَص عناصره وتضاف إلى مصفوفة جديدة.

flatten!‎

يشبه التابع flatten!‎ التابع flatten في جميع النواحي باستثناء أنه لا يضع الناتج في مصفوفة جديدة وإنما يعدِّل على المصفوفة الأصلية نفسها.

frozen?‎‎

يتحقق التابع frozen?‎ إن كانت مصفوفةٌ مُجمَّدةً (frozen) بشكل دائم أو مؤقت إلى حين إعادة ترتيبها.

hash

يعيد القيمة Hash للمصفوفة التي استُدعيت معه.

include?‎‎

[]

يجلب المعامل [] عنصرًا ذي فهرس محدد، أو جزءًا محددًا ببداية وطول، أو مجالًا محددًا ببداية ونهاية من مصفوفة.

index

يجلب فهرس أول ظهور لعنصر محدَّد من مصفوفة (يتحقق من التساوي باستعمال المعامل ==) أو فهرس أول عنصر يحقق شرطًا محدَّدًا.

initialize_copy

يبدل محتوى المصفوفة المُمرّرة إليه مكان محتوى المصفوفة التي استُدعيت معه مع تغيير طول المصفوفة عند الضرورة.

insert

يُدرج  القيم المُمرّرة إليه قبل عنصرٍ ذي فهرس محدد.

inspect

يحول مصفوفةً إلى سلسلة نصية.

join

يجمع  جميع عناصر المصفوفة التي استُدعيت معها سويةً في سلسلة نصية ويفصل بينها بفاصل معين.

keep_if

يٌبقِي  على جميع عناصر المصفوفة التي تحقق شرطًا معينًا ويحذف العناصر الأخرى المتبقية.

last

يجلب آخر عنصر أو آخر n عنصر من مصفوفة.

length

يعيد  عدد عناصر المصفوفة التي استُدعيت معه.

map

يستدعي  كتلة برمجية محدَّدة مع كل عنصر من عناصر مصفوفة ثمَّ يضع الناتج الذي تعيده هذه الكتلة لكل عنصر في مصفوفة جديدة وتعيدها.

!map

يستدعي  كتلة برمجية محدَّدة مع كل عنصر من عناصر مصفوفة ثمَّ يضع القيمة التي أعادتها تلك الكتلة مكان العنصر الذي طُبِّقَت عليه.

max

يعيد أكبر عنصر موجود في المصفوفة التي استُدعيت معه.

min

يعيد  أصغر عنصر موجود في المصفوفة التي استُدعيت معه.

pack

يُحزِّمُ (packs) التابع pack محتويات المصفوفة التي استُدعيت معه على شكل تسلسل ثنائي (binary sequence) وفقًا للمُوجِّهات (directives) الواردة في المعامل aTemplateString؛

permutation

يعيد  كل التبديلات (permutations) الممكنة لجميع عناصر مصفوفة،

pop

يحذف آخر عنصر أو آخر n عنصر من مصفوفة ثم يعيده أو يعيدها في مصفوفة جديدة.

prepend

يعدُّ هذا التابع اسمًا بديلًا للتابع unshift.

product

يوزِّع  عناصر المصفوفة التي استدعيت معه على جميع عناصر المصفوفات الممرَّرة إليه.

push

يضيف جميع الكائنات المُمرّرة إليه إلى نهاية المصفوفة التي استُدعيت معه.

rassoc

reject

reject!‎

repeated_combination

repeated_permutation

replace

reverse

reverse!‎

reverse_each

rindex

rotate

rotate!‎

sample

select

select!‎

shift

shuffle

shuffle!‎

size

slice

slice!‎

sort

sort!‎

sort_by!‎

sum

take

take_while

to_a

to_ary

to_h

to_s

transpose

uniq

uniq!‎

unshift

values_at

zip

|

مصادر