القوائم في لغة البرمجة R: كيفية إنشاء العناصر وتحديدها

⚡ ملخص ذكي

قائمة R هي كائن يخزن المتجهات والمصفوفات وإطارات البيانات وحتى القوائم الأخرى داخل حاوية واحدة. تقوم الدالة list() بإنشائها، وتستخرج الأقواس المربعة المزدوجة أي عنصر منها.

  • 🧺 التخزين المختلط: تحتوي القائمة على كائنات من أنواع وأطوال مختلفة، وهو ما لا يستطيع المتجه البسيط فعله.
  • 🛠️ خطوة البناء: تقوم الدالة list(vect, mat, df) بتجميع متجه ومصفوفة وإطار بيانات في كائن واحد.
  • 🔢 الوصول إلى الوظيفة: my_list[[2]] تُرجع العنصر نفسه، بينما my_list[2] تُرجع قائمة مكونة من عنصر واحد.
  • 🏷️ العناصر المسماة: تتيح عملية وضع علامات على العناصر عند إنشائها الوصول إليها من خلال عامل التشغيل $ أو [[“name”]].
  • ✏️ التعديلات المباشرة: إعادة التعيين تُحدّث عنصرًا، وتعيين قيمة NULL يُزيله من القائمة.
  • 🔗 تسطيح: تقوم الدالة unlist() بدمج قائمة متداخلة في متجه واحد ذري ​​لتحليلها لاحقًا.

إنشاء قائمة في لغة البرمجة R وتحديد عناصرها

ما هي قائمة R؟

قائمة R هو كائن في برمجة R يتضمن مصفوفات أو نواقل أو إطارات بيانات أو قوائم بداخلها. تُستخدم قائمة R أيضًا لتخزين مجموعة من الكائنات واستخدامها عندما نحتاج إليها. يمكننا أن نتخيل قائمة R كحقيبة لوضع العديد من العناصر المختلفة. عندما نحتاج إلى استخدام أحد العناصر، يمكننا فتح الحقيبة واستخدامها.

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

بناء جملة القائمة في R

يمكننا استخدام الدالة list() لإنشاء قوائم في لغة البرمجة R:

list(element_1, ...)
arguments:
-element_1: store any type of R object
-...: pass as many objects as specifying. each object needs to be separated by a comma

يمكن تمرير كل وسيط بشكل مباشر أو بالشكل التالي العلامة = القيمةيصبح الوسيط المجرد عنصرًا موضعيًا لا يمكن الوصول إليه إلا برقمه، بينما يكتسب الوسيط الموسوم اسمًا أيضًا. مرجع R الأساسي لـ قائمة() يوثق كلا الشكلين ويشير إلى أن unlist() يعمل كمعكوس تقريبي لـ as.list().

كيفية إنشاء قائمة في R

فيما يلي عملية خطوة بخطوة حول كيفية إنشاء قائمة في R:

في المثال أدناه، سنقوم بإنشاء ثلاثة كائنات مختلفة، Vector، وMatrix، وa إطار البيانات باستخدام وظيفة القائمة في R.

الخطوة 1) إنشاء ناقل

استخدم الكود أدناه لإنشاء متجه في R

# Vector with numeric from 1 up to 5
vect  <- 1:5

يقوم عامل النقطتين ببناء التسلسل 1، 2، 3، 4، 5 كمتجه عدد صحيح، ويقوم سهم التعيين بتخزينه تحت اسم vect.

الخطوة 2) إنشاء مصفوفة

الآن، أنشئ مصفوفة باستخدام الكود التالي

# A 2x 5 matrix
mat  <- matrix(1:9, ncol = 5)
dim(mat)

هناك تفصيلان جديران بالملاحظة هنا. تحتاج شبكة مكونة من صفين وخمسة أعمدة إلى عشر قيم، ولكن لم يتم توفير سوى تسع قيم، لذا يعيد برنامج R استخدام التسلسل ويطبع تحذيرًا بأن طول البيانات ليس من مضاعفات عدد الصفوف. هذه القيمة المعاد استخدامها هي سبب انتهاء الصف الثاني من المصفوفة المطبوعة بالرقم 1 بدلاً من 10. ثم يُبلغ استدعاء الدالة dim() عن شكل الشبكة.

الإخراج:

## [1] 2 5

الخطوة 3) إنشاء إطار البيانات

قم بإنشاء إطار بيانات في R باستخدام الكود أدناه

# select the 10th row of the built-in R data set EuStockMarkets
df <- EuStockMarkets[1:10,]

يشير التعليق إلى الصف العاشر، لكن التعبير يحتفظ بالصفوف من 1 إلى 10 من سلسلة EuStockMarkets المدمجة. كما أن عملية التحديد الجزئي تحذف فئة السلسلة الزمنية، لذا فإن الناتج هو مصفوفة رقمية وليست إطار بيانات حقيقي، وهذا تحديدًا سبب احتواء النتيجة المطبوعة أدناه على تسميات صفوف على شكل [1,] بدلًا من أسماء الصفوف. استخدم الدالة as.data.frame() عند الحاجة إلى إطار بيانات حقيقي.

الخطوة 4) إنشاء قائمة في R

الآن، يمكننا وضع الكائنات الثلاثة في قائمة R باستخدام الكود أدناه

# Construct list with these vec, mat, and df:
my_list <- list(vect, mat, df)
my_list

الإخراج:

## [[1]]
## [1] 1 2 3 4 5

## [[2]]
##       [,1] [,2] [,3] [,4] [,5]
## [1,]    1    3    5    7    9
## [2,]    2    4    6    8    1

## [[3]]
##          DAX    SMI    CAC   FTSE
##  [1,] 1628.75 1678.1 1772.8 2443.6
##  [2,] 1613.63 1688.5 1750.5 2460.2
##  [3,] 1606.51 1678.6 1718.0 2448.2
##  [4,] 1621.04 1684.1 1708.1 2470.4
##  [5,] 1618.16 1686.6 1723.1 2484.7
##  [6,] 1610.61 1671.6 1714.3 2466.8
##  [7,] 1630.75 1682.9 1734.5 2487.9
##  [8,] 1640.17 1703.6 1757.4 2508.4
##  [9,] 1635.47 1697.5 1754.0 2510.5
##  [10,] 1645.89 1716.3 1754.3 2497.4

تمثل العناوين الثلاثة بين قوسين مزدوجين في هذا الناتج مواقع القائمة. لم يتم تسطيح أي شيء أو تحويله: العنصر الأول لا يزال متجهًا عدديًا صحيحًا، والعنصر الثاني لا يزال مصفوفة، والعنصر الثالث لا يزال يحتوي على جميع صفوف أسعار الأسهم العشرة.

حدد عناصر من قائمة R

بعد إنشاء قائمتنا، يُمكننا الوصول إليها بسهولة. نحتاج إلى استخدام [[index]] لتحديد عنصر في القائمة. القيمة الموجودة داخل القوسين المربعين المزدوجين تُمثل موضع العنصر في القائمة التي نريد الوصول إليها.tracعلى سبيل المثال، إذا مررنا الرقم 2 داخل الأقواس، فإن R تُرجع العنصر الثاني المدرج.

الآن في هذا البرنامج التعليمي Rفلنحاول تحديد العنصر الثاني من القوائم في R المسمى my_list، نستخدم my_list[[2]]

# Print second element of the list
my_list[[2]]

الإخراج:

##      [,1] [,2] [,3] [,4] [,5]
## [1,]    1    3    5    7    9
## [2,]    2    4    6    8    1

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

التعبير ما الذي سيعود؟ فئة النتيجة استخدمه عندما
my_list[[2]] العنصر المخزن نفسه مهما كان ما تم تخزينه، هنا مصفوفة عليك إجراء عملية حسابية على عنصر واحد
my_list[2] قائمة فرعية تحتوي على ذلك العنصر الواحد الإدارية يجب عليك الاحتفاظ بغلاف القائمة
my_list[c(1, 3)] قائمة فرعية بالعناصر المختارة الإدارية أنت بحاجة إلى عدة عناصر في وقت واحد
my_list[-2] كل عنصر باستثناء العنصر الثاني الإدارية عليك حذف عنصر
# Compare the two bracket styles
class(my_list[[2]])   # the matrix itself
class(my_list[2])     # a list of length one

# Several elements, and everything but one element
my_list[c(1, 3)]
my_list[-2]

القوائم المسماة في لغة R

تُعدّ الفهارس الموضعية هشة: فعند إدخال عنصر واحد، يتحرك كل رقم يليه. يُزيل تسمية العناصر هذا الخطر، ويجعل الكود متوافقًا مع البيانات التي يصفها. يمكن تحديد الأسماء عند إنشاء القائمة، أو إضافتها لاحقًا باستخدام الدالة names().

# Tag each element at creation time
named_list <- list(numbers = vect, grid = mat, prices = df)

# Three ways to reach the same element
named_list$grid
named_list[["grid"]]
named_list["grid"]      # returns a one-element list

# Read or replace the names later
names(named_list)
names(named_list)[2] <- "grid_2x5"

يختلف عامل $ والأقواس المزدوجة في جانب واحد يُوقع المبتدئين في الخطأ. يُجري عامل $ مطابقة جزئية، لذا فإن named_list$pri لا يزال يجد الأسعار، بينما تُرجع named_list[[“pri”]] قيمة NULL لأن الأقواس المزدوجة تُطابق تمامًا ما لم يتم تمرير exact = FALSE. تُعدّ المطابقة الجزئية مُريحة في سطر الأوامر، ولكنها غير آمنة في البرامج النصية، لذا يُفضّل استخدام الصيغة الدقيقة في الكود المحفوظ.

# A compact map of the whole structure
str(named_list)

تقوم الدالة str() بطباعة سطر واحد لكل عنصر مع نوعه وحجمه، وهي أسرع طريقة للتأكد من أن القائمة تحتوي على ما تتوقعه قبل الوصول إلى عناصرها.

تعديل وإضافة وحذف العناصر في قائمة R

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

# Replace an element in place
named_list[["numbers"]] <- 1:10

# Add a new element simply by naming it
named_list[["created"]] <- Sys.Date()

# Append without a name: the element lands at the end
named_list <- append(named_list, list(TRUE))

# Delete an element by assigning NULL to it
named_list[["created"]] <- NULL
  • يحل محل: يؤدي تعيين اسم موجود إلى استبدال ذلك العنصر وترك موضعه دون تغيير.
  • إضافة: يؤدي تعيين اسم غير موجود إلى إضافة عنصر جديد في نهاية القائمة.
  • ألحق: تأخذ الدالة append() قائمة كمعامل ثانٍ، لذا قم بتغليف القيمة المجردة في list() قبل تمريرها.
  • حذف: يؤدي تعيين قيمة NULL باستخدام الأقواس المزدوجة إلى إزالة العنصر وتقصير القائمة.

إحدى النتائج التي يقع فيها المستخدمون بشكل متكرر: بما أن NULL تعني الحذف، فلا يمكنك تخزين قيمة NULL فعلية باستخدام الأقواس المزدوجة. استخدم بدلاً من ذلك التعيين باستخدام قوس واحد، كما في named_list[“empty”] <- list(NULL)، والذي يحتفظ بالخانة ويضع NULL بداخلها.

القوائم المتداخلة ودالة unlist() في لغة R

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

# A list whose elements are themselves lists
project <- list(
  meta = list(owner = "analyst", year = 2026),
  data = list(vect, mat)
)

# Chain the accessors to reach an inner value
project$meta$year
project[["data"]][[2]]

# Flatten every level into one atomic vector
flat <- unlist(project)

# Strip a single level and keep the rest as a list
half <- unlist(project, recursive = FALSE)

للتسطيح تكلفةٌ تستحق الفهم. يجب أن تُعيد الدالة unlist() متجهًا واحدًا، لذا فهي تُحوّل كل قيمة إلى النوع الأكثر عموميةً الموجود، وفقًا للترتيب التالي: منطقي، عدد صحيح، عدد عشري، حرفي. وبالتالي، فإن القائمة المتداخلة التي تمزج الأرقام بالنصوص تُعاد كنصٍّ بالكامل. تُبنى أسماء النتائج بدمج الوسوم الخارجية والداخلية، ولهذا السبب يصل العنصر كـ meta.owner بدلًا من owner.

استخدم `use.names = FALSE` عندما تكون الأسماء المركبة غير مرغوب فيها، واضبط `recursive = FALSE` عندما تريد إزالة الطبقة الخارجية فقط. إذا كان يجب الاحتفاظ بأنواع القيم، فاترك البنية سليمة وتعامل مع القائمة بدلاً من تسطيحها.

إطار بيانات مدمج في R

غالبًا ما تُملأ القوائم ببيانات مقروءة من القرص أو من الإنترنت، لذا من المفيد معرفة كيفية وصول إطار البيانات قبل تخزينه داخلها. قبل إنشاء إطار بيانات خاص بنا، يمكننا إلقاء نظرة على مجموعة بيانات R المتاحة عبر الإنترنت. تتكون مجموعة بيانات السجن من 714×5 أبعاد. يمكننا إلقاء نظرة سريعة على الجزء السفلي من إطار البيانات باستخدام الدالة tail(). وبالمثل، تعرض الدالة head() الجزء العلوي من إطار البيانات. يمكنك تحديد عدد الصفوف المعروضة باستخدام head(df, 5). سنتعرف على المزيد حول الدالة read.csv() في... استيراد البيانات في R البرنامج التعليمي.

PATH <-'https://raw.githubusercontent.com/guru99-edu/R-Programming/master/prison.csv'
df <- read.csv(PATH)[1:5]
head(df, 5)

الإخراج:

##   X state year govelec black
## 1 1     1   80       0 0.2560
## 2 2     1   81       0 0.2557
## 3 3     1   82       1 0.2554
## 4 4     1   83       0 0.2551
## 5 5     1   84       0 0.2548

يُحدد الجزء [1:5] الذي يلي استدعاء الدالة read.csv() الأعمدة الخمسة الأولى، وليس الصفوف الخمسة الأولى، لأن إطار البيانات هو في حد ذاته قائمة من الأعمدة. يؤدي استخدام فهرسة الأقواس المفردة على قائمة إلى إرجاع قائمة أصغر، وهذه القائمة الأصغر هي أيضاً إطار بيانات.

يمكننا التحقق من بنية إطار البيانات باستخدام str:

# Structure of the data
str(df)

الإخراج:

## 'data.frame':    714 obs. of  5 variables:
##  $ X      : int  1 2 3 4 5 6 7 8 9 10 ...
##  $ state  : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ year   : int  80 81 82 83 84 85 86 87 88 89 ...
##  $ govelec: int  0 0 1 0 0 0 1 0 0 0 ...
##  $ black  : num  0.256 0.256 0.255 0.255 0.255 ...

يتم تخزين كافة المتغيرات في عددي التنسيق. البادئة $ في كل سطر هي نفس المعامل المستخدم في القوائم المسماة سابقًا، مما يؤكد أن إطار البيانات عبارة عن قائمة من الأعمدة متساوية الطول تحمل تسمية مستطيلة. وبالتالي، فإن كل ما تعلمناه عن تسمية عناصر القائمة وتحديدها وحذفها ينتقل مباشرةً إلى أنواع بيانات R وإلى أعمدة إطار البيانات.

الأسئلة الشائعة

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

استدعِ الدالة is.list(x)، التي تُرجع القيمة TRUE للقوائم وقوائم الأزواج. تُبلغ الدالة class(x) عن نوع الكائن، بينما تُرجع الدالة typeof(x) القيمة "list" حتى بالنسبة لإطارات البيانات، لأن إطار البيانات عبارة عن قائمة من الأعمدة متساوية الطول.

تحسب الدالة length(my_list) عناصر المستوى الأعلى فقط، لذا تُحسب القوائم المتداخلة كقائمة واحدة. بينما تُبلغ الدالة lengths(my_list) عن حجم كل عنصر في استدعاء واحد، وهو أسرع وأوضح من الدالة loo.ping عندما تختلف العناصر.

تُطبّق الدالة `lapply(my_list, FUN)` وظيفة تُمرَّر الدالة `sapply()` على كل عنصر وتُعيد قائمة. تُبسِّط الدالة `sapply()` النتيجة إلى متجه أو مصفوفة حيثما أمكن. كما أن استخدام حلقة `for` عادية على `seq_along(my_list)` يُجدي نفعًا ويُقرأ بوضوح.

عندما يكون لكل عنصر نفس الطول، تعمل الدالة `as.data.frame(my_list)` مباشرةً. أما بالنسبة لقائمة من الصفوف متساوية العرض، فإن الدالة `do.call(rbind, my_list)` تقوم بتكديسها أولاً. com.dplyr يوفر النظام البيئي الدالة as_tibble() عندما يجب أن تبقى أنواع الأعمدة دون تغيير.

لا تحتوي القوائم على خاصية فرز مدمجة، لذا على سبيل المثالtracيُعيد ترتيب عناصر القائمة حسب حجمها باستخدام المفتاح المقارن أولاً: my_list[order(sapply(my_list, length))] . بالنسبة للبيانات المستطيلة، يتم تحويلها إلى إطار و فرز إطار البيانات باستخدام order() بدلاً من ذلك.

تقوم المساعدات الذكية بقراءة مخرجات الدالة str() وشرح سبب إرجاع فهرس ما قيمة NULL أو قائمة فرعية بدلاً من قيمة حقيقية. كما تقترح الصيغة الصحيحة للأقواس، وتصمم مسارات معالجة البيانات باستخدام الدالة lapply()، وتُشير إلى أي تحويل غير مقصود للأنواع قبل أن يُفسد النتيجة.

نعم. مساعد الطيار جيثب يعمل في RStudio في الإصدار 2023.09.0 والإصدارات الأحدث، يمكنك الوصول إلى هذه الميزة من خلال الأدوات، ثم الخيارات العامة، ثم إعدادات مساعد التعليمات البرمجية. تُكمل هذه الميزة استدعاءات list() و names() و unlist() من تعليق، مع العلم أن كل اقتراح لا يزال بحاجة إلى مراجعة.

تلخيص هذه التدوينة بـ: