🧱 القوائم المتعددة الأبعاد (Multi-Dimensional List) في Dart
🔹 وتُعرف أيضًا بـ القوائم المتداخلة أو المصفوفات الثنائية.
✅ ما هي Multi-Dimensional List؟
هي قائمة تحتوي على قوائم بداخلها.
مثال:
List<List<int>> matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];JavaScript↪ هذا يمثل “مصفوفة” 3 صفوف × 3 أعمدة.
🧠 لماذا نستخدمها؟
- تمثيل الجداول.
- تمثيل بيانات الصفوف والأعمدة (مثل قواعد البيانات).
- إنشاء ألعاب شبكية (مثل Tic-Tac-Toe).
- بيانات الطلاب والدرجات، إلخ…
🔹 كيفية إنشاء قائمة ثنائية الأبعاد:
إما مباشرة:
List<List<String>> names = [
['Ali', 'Sara'],
['Omar', 'Lina'],
];JavaScriptأو ديناميكيًا:
List<List<int>> grid = List.generate(3, (i) => List.generate(3, (j) => 0));JavaScript⬅ ينشئ مصفوفة 3×3 مملوءة بالأصفار.
🟦 الوصول إلى عنصر داخل القائمة المتداخلة
print(matrix[0][1]); // النتيجة: 2JavaScript↪ matrix[0] تعني الصف الأول
↪ [1] تعني العنصر الثاني من هذا الصف
🔁 التكرار على القوائم المتعددة الأبعاد
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
print('Element at [$i][$j] = ${matrix[i][j]}');
}
}JavaScript🔄 باستخدام for-in:
for (var row in matrix) {
for (var value in row) {
print(value);
}
}JavaScript✍️ مثال تطبيقي
جدول درجات الطلاب
List<List<int>> grades = [
[90, 85, 88], // درجات الطالب 1
[70, 75, 72], // الطالب 2
[100, 98, 99], // الطالب 3
];
// طباعة متوسط درجات كل طالب
for (int i = 0; i < grades.length; i++) {
double avg = grades[i].reduce((a, b) => a + b) / grades[i].length;
print('Student ${i + 1} average: $avg');
}JavaScript✳️ استبدال عنصر داخل القائمة المتعددة
matrix[2][1] = 100; // استبدال العنصر في الصف الثالث والعمود الثانيJavaScript🟡 هل يمكن أن تكون ثلاثية أو أكثر؟
نعم، يمكن أن تكون قائمة من قائمة من قائمة:
List<List<List<int>>> cube = [
[
[1, 2],
[3, 4]
],
[
[5, 6],
[7, 8]
]
];JavaScript✅ ملخص سريع
| المفهوم | المثال |
|---|---|
| إنشاء قائمة 2D | List<List<int>> matrix = [...] |
| الوصول لعنصر | matrix[row][col] |
| تعديل عنصر | matrix[1][2] = 99 |
| التكرار داخل 2D List | for داخل for |
| إنشاء ديناميكي | List.generate(...) |
🔁 Spread Operator في Dart
وهو جزء مهم جدًا عند التعامل مع القوائم (Lists)، وخصوصًا عند دمج القوائم أو نسخ عناصرها.
✅ ما هو الـ Spread Operator؟
هو الرمز: ...
يُستخدم لنسخ جميع عناصر قائمة داخل قائمة أخرى.
🟢 مثال بسيط:
List<int> list1 = [1, 2, 3];
List<int> list2 = [4, 5, 6];
List<int> combined = [...list1, ...list2];
print(combined); // [1, 2, 3, 4, 5, 6]JavaScript📌 بدون spread:
List<int> combined = [list1, list2]; // ❌ هذا ينشئ قائمة داخل قائمة
print(combined); // [[1, 2, 3], [4, 5, 6]]
******************************************
List<int> combined = [];
combined.addAll(list1);
combined.addAll(list2);
print(combined); // [1, 2, 3, 4, 5, 6]JavaScript🟡 الشرطية مع spread (Null-Aware Spread)
إذا كانت القائمة قد تكون null، نستخدم ...?
List<int>? optionalList = null;
List<int> result = [0, ...?optionalList, 100];
print(result); // [0, 100] بدون خطأ
//////////////////////////////////////////////
List<int> combined = [];
combined.addAll(list1);
combined.addAll(list2);
print(combined); // [1, 2, 3, 4, 5, 6]JavaScriptلو استعملت
...optionalListبدون?، سيحدث خطأ إذا كانتnull.
🧠 استخدام عملي: إنشاء قائمة جديدة من قائمة مع إضافة عناصر
List<String> base = ['PHP', 'Dart'];
List<String> withNew = [...base, 'JavaScript'];
print(withNew); // ['PHP', 'Dart', 'JavaScript']JavaScript🛠️ استخدام مع الشروط (Collection if)
bool addJS = true;
List<String> langs = [
'PHP',
'Dart',
if (addJS) ...['JavaScript', 'TypeScript']
];
print(langs); // ['PHP', 'Dart', 'JavaScript', 'TypeScript']JavaScript🔄 مقارنة النسخ اليدوي مقابل spread
✅ الطريقة اليدوية:
List<int> a = [1, 2, 3];
List<int> b = [];
for (var x in a) {
b.add(x);
}JavaScript✅ مع spread:
List<int> b = [...a];JavaScriptأسرع وأوضح!
✅ ملخص
| الاستخدام | المثال |
|---|---|
| دمج قائمتين | [...] |
| إضافة عناصر من قائمة إلى أخرى | newList = [...list1, 'item'] |
التعامل مع null | ...?list |
| مع شرط | if (condition) ...[items] |
🔍 دالة where() في Dart
✅ ما هي where()؟
هي دالة تُستخدم مع القوائم (List) و المجموعات (Set) و الخرائط (Map) لتصفية العناصر حسب شرط معين.
ترجع where() كائنًا من النوع Iterable يحتوي على العناصر التي تنطبق عليها الشروط.
✅ الصيغة العامة:
list.where((element) => شرط)JavaScript- ترجع قائمة جديدة تحتوي فقط على العناصر التي تحقق الشرط.
- لا تؤثر على القائمة الأصلية.
- يمكن تحويل الناتج إلى
Listباستخدام.toList()إذا أردت استخدامه كقائمة عادية.
🧠 فوائد where():
| الفائدة | الشرح |
|---|---|
| 🔎 التصفية | استخراج عناصر مطابقة لشرط معين |
| ✅ تسهيل القراءة | أكثر وضوحًا من for مع if |
| 🔁 قابلة للسلسلة | يمكن دمجها مع map() أو reduce() |
| 📋 لا تعدل الأصل | تُعيد نسخة مصفاة دون تغيير القائمة الأصلية |
🟢 أين تُستخدم؟
- تصفية أرقام أو أسماء.
- البحث عن عناصر تحقق شروط.
- التعامل مع بيانات الطلاب، المنتجات، الخ…
- تقليص النتائج أو تحليل البيانات.
✳️ مثال 1: تصفية الأرقام الزوجية
List<int> numbers = [1, 2, 3, 4, 5, 6];
var evens = numbers.where((n) => n % 2 == 0).toList();
print(evens); // [2, 4, 6]JavaScript✳️ مثال 2: تصفية أسماء تبدأ بحرف معيّن
List<String> names = ['Ali', 'Sara', 'Omar', 'Salma'];
var sNames = names.where((name) => name.startsWith('S')).toList();
print(sNames); // [Sara, Salma]JavaScript✳️ مثال 3: تصفية درجات النجاح فقط
List<int> grades = [45, 75, 60, 30, 80];
var passed = grades.where((grade) => grade >= 50).toList();
print(passed); // [75, 60, 80]JavaScript✳️ مثال 4: تصفية منتجات غالية الثمن
List<Map<String, dynamic>> products = [
{'name': 'Phone', 'price': 500},
{'name': 'Watch', 'price': 150},
{'name': 'Laptop', 'price': 1000},
];
var expensive = products.where((p) => p['price'] > 400).toList();
print(expensive);
// [{'name': 'Phone', 'price': 500}, {'name': 'Laptop', 'price': 1000}]JavaScript⚠️ ملاحظة مهمة:
where()تُعيدIterable، وليسListمباشرة.- استخدم
.toList()لتحويل النتيجة إلىListعند الحاجة.
✅ ملخص سريع
| السؤال | الجواب |
|---|---|
| ماذا تفعل؟ | تُرجع عناصر مطابقة لشرط |
| هل تغير القائمة الأصلية؟ | ❌ لا |
| هل يجب تحويل الناتج إلى List؟ | يفضل: toList() |
هل يمكن استخدامها مع map أو reduce؟ | ✅ نعم |
🔍 شرح مفصل لـ:
where()firstWhere()whereType<T>()
مع أمثلة لكل واحدة وتوضيح متى نستخدم كل واحدة منها.
🟢 1. where()
✅ ما تفعل:
ترجع جميع العناصر التي تحقق شرطًا معينًا.
✅ النوع الذي تُرجعه:
Iterable<T> → ويمكن تحويله إلى List باستخدام .toList().
📌 مثال 1: تصفية الأعداد الزوجية
List<int> numbers = [1, 2, 3, 4, 5, 6];
var evens = numbers.where((n) => n % 2 == 0).toList();
print(evens); // [2, 4, 6]JavaScript📌 مثال 2: تصفية أسماء تبدأ بحرف “A”
List<String> names = ['Ali', 'Omar', 'Ahmed', 'Sara'];
var aNames = names.where((name) => name.startsWith('A')).toList();
print(aNames); // [Ali, Ahmed]JavaScript✅ متى نستخدم where()؟
عندما نريد كل العناصر التي تحقق شرطًا معينًا.
🟢 2. firstWhere()
✅ ما تفعل:
ترجع أول عنصر فقط يحقق شرطًا معينًا.
لو لم يوجد، يمكن إرجاع قيمة افتراضية.
✅ النوع الذي تُرجعه:
T → قيمة مفردة من نفس نوع العناصر.
📌 مثال 1: أول رقم أكبر من 10
List<int> numbers = [3, 7, 15, 20];
int first = numbers.firstWhere((n) => n > 10);
print(first); // 15JavaScript📌 مثال 2: استخدام قيمة افتراضية إذا لم يوجد شيء
List<String> names = ['Sara', 'Lina'];
String result = names.firstWhere(
(name) => name.startsWith('Z'),
orElse: () => 'Not Found',
);
print(result); // Not FoundJavaScript✅ متى نستخدم firstWhere()؟
عندما نريد عنصرًا واحدًا فقط يطابق الشرط (غالبًا أول عنصر).
🟢 3. whereType<T>()
✅ ما تفعل:
تُرجع العناصر التي تنتمي لنوع معيّن فقط من القائمة.
✅ مفيدة عند التعامل مع قائمة تحتوي أنواع مختلفة.
📌 مثال: استخراج الأعداد فقط من قائمة مختلطة
List<dynamic> mixed = [1, 'hello', true, 2.5, 42];
var onlyInts = mixed.whereType<int>().toList();
print(onlyInts); // [1, 42]JavaScript📌 مثال: استخراج السلاسل النصية فقط
List<dynamic> mixed = ['Hi', 100, 'World', false];
var strings = mixed.whereType<String>().toList();
print(strings); // ['Hi', 'World']JavaScript✅ متى نستخدم whereType<T>()؟
عندما تكون قائمتك تحتوي على أنواع بيانات متعددة وتريد استخراج نوع محدد فقط (مثل فقط النصوص، أو الأرقام).
🟡 ملخص المقارنة:
| الدالة | ما تُرجعه | تُستخدم عندما… |
|---|---|---|
where() | Iterable<T> | تريد كل العناصر التي تحقق شرطًا |
firstWhere() | T (عنصر واحد) | تريد أول عنصر فقط يحقق شرطًا |
whereType<T>() | Iterable<T> | تريد تصفية حسب النوع فقط |