حتى الآن، تعلمنا عن هياكل البيانات المعقدة التالية:
يتم استخدام الكائنات لتخزين المجموعات ذات المفاتيح.
يتم استخدام المصفوفات لتخزين المجموعات المطلوبة.
لكن هذا لا يكفي للحياة الحقيقية. ولهذا السبب توجد Map
Set
أيضًا.
الخريطة عبارة عن مجموعة من عناصر البيانات ذات المفاتيح، تمامًا مثل Object
. لكن الاختلاف الرئيسي هو أن Map
تسمح بمفاتيح من أي نوع.
الطرق والخصائص هي:
new Map()
- تنشئ الخريطة.
map.set(key, value)
- يخزن القيمة بالمفتاح.
map.get(key)
- يُرجع القيمة حسب المفتاح، undefined
في حالة عدم وجود key
في الخريطة.
map.has(key)
- يُرجع true
في حالة وجود key
، false
في حالة عدم ذلك.
map.delete(key)
- يزيل العنصر (زوج المفتاح/القيمة) بالمفتاح.
map.clear()
- يزيل كل شيء من الخريطة.
map.size
- يُرجع عدد العناصر الحالي.
على سبيل المثال:
دع الخريطة = خريطة جديدة ()؛ Map.set('1', 'str1'); // مفتاح سلسلة Map.set(1, 'num1'); // مفتاح رقمي Map.set(true, 'bool1'); // مفتاح منطقي // هل تتذكر الكائن العادي؟ فإنه تحويل المفاتيح إلى سلسلة // تحتفظ الخريطة بالنوع، لذا فإن هذين النوعين مختلفان: تنبيه(map.get(1)); // "رقم 1" تنبيه(map.get('1')); // "ستر1" تنبيه(map.size); // 3
كما نرى، على عكس الكائنات، لا يتم تحويل المفاتيح إلى سلاسل. أي نوع من المفاتيح ممكن.
map[key]
ليست الطريقة الصحيحة لاستخدام Map
على الرغم من أن map[key]
تعمل أيضًا، على سبيل المثال، يمكننا ضبط map[key] = 2
، وهذا يعني التعامل مع map
ككائن جافا سكريبت عادي، لذا فهي تتضمن جميع القيود المقابلة (فقط مفاتيح السلسلة/الرموز وما إلى ذلك).
لذلك يجب علينا استخدام طرق map
: set
و get
وما إلى ذلك.
يمكن للخريطة أيضًا استخدام الكائنات كمفاتيح.
على سبيل المثال:
دع جون = { الاسم: "جون" }; // لكل مستخدم، دعونا نخزن عدد زياراتهم السماح للزياراتCountMap = new Map(); // جون هو مفتاح الخريطة VisitCountMap.set(john, 123); تنبيه (الزياراتCountMap.get(جون) ); // 123
يعد استخدام الكائنات كمفاتيح أحد أبرز وأهم ميزات Map
. الشيء نفسه لا يحسب بالنسبة Object
. السلسلة كمفتاح في Object
جيدة، لكن لا يمكننا استخدام Object
آخر كمفتاح في Object
.
دعونا نحاول:
دع جون = { الاسم: "جون" }; دع بن = { الاسم: "بن" }; دع الزياراتCountObj = {}; // حاول استخدام كائن visitCountObj[ben] = 234; // حاول استخدام كائن ben كمفتاح visitCountObj[john] = 123; // حاول استخدام كائن john كمفتاح، وسيتم استبدال كائن ben // هذا ما كتب! تنبيه (الزياراتCountObj["[كائن كائن]"])؛ // 123
نظرًا لأن visitsCountObj
عبارة عن كائن، فإنه يحول جميع مفاتيح Object
، مثل john
و ben
أعلاه، إلى نفس السلسلة "[object Object]"
. بالتأكيد ليس ما نريده.
كيف تقارن Map
المفاتيح
لاختبار مفاتيح التكافؤ، يستخدم Map
الخوارزمية SameValueZero. إنها تقريبًا نفس المساواة الصارمة ===
، لكن الفرق هو أن NaN
تعتبر مساوية لـ NaN
. لذلك يمكن استخدام NaN
كمفتاح أيضًا.
لا يمكن تغيير هذه الخوارزمية أو تخصيصها.
تسلسل
يُرجع كل استدعاء map.set
الخريطة نفسها، حتى نتمكن من "تسلسل" الاستدعاءات:
Map.set('1', 'str1') .set(1, 'num1') .set(صحيح, 'bool1');
للتكرار على map
، هناك ثلاث طرق:
map.keys()
- يُرجع عنصرًا قابلاً للتكرار للمفاتيح،
map.values()
- ترجع تكرارًا للقيم،
map.entries()
- يُرجع تكرارًا للإدخالات [key, value]
، ويتم استخدامه افتراضيًا في for..of
.
على سبيل المثال:
دع وصفة الخريطة = خريطة جديدة([ ['الخيار'، 500]، ["الطماطم"، 350]، ['البصل'، 50] ])؛ // التكرار على المفاتيح (الخضروات) لـ (اسمح للخضروات بالصفة Map.keys ()) { تنبيه(الخضار); // خيار، طماطم، بصل } // التكرار على القيم (الكميات) لـ (اسمحوا بكمية وصفة Map.values()) { تنبيه (المبلغ)؛ // 500، 350، 50 } // التكرار على إدخالات [المفتاح، القيمة]. لـ (السماح بإدخال وصفة Map) {// نفس ما هو موجود في descriptionMap.entries() تنبيه (إدخال)؛ // الخيار، 500 (وهلم جرا) }
يتم استخدام أمر الإدراج
يتم التكرار بنفس الترتيب الذي تم به إدراج القيم. تحافظ Map
على هذا الترتيب، على عكس Object
العادي.
بالإضافة إلى ذلك، يحتوي Map
على طريقة forEach
مدمجة، تشبه Array
:
// يقوم بتشغيل الوظيفة لكل زوج (مفتاح، قيمة). وصفةMap.forEach( (القيمة، المفتاح، الخريطة) => { تنبيه(`${مفتاح}: ${value}`); // خيار: 500 إلخ });
عندما يتم إنشاء Map
، يمكننا تمرير مصفوفة (أو قابلة للتكرار أخرى) مع أزواج المفاتيح/القيمة للتهيئة، مثل هذا:
// مصفوفة من أزواج [المفتاح، القيمة] دع الخريطة = خريطة جديدة([ ['1'، 'str1']، [1، 'رقم 1']، [صحيح، 'bool1'] ]); تنبيه(map.get('1')); // str1
إذا كان لدينا كائن عادي، ونرغب في إنشاء Map
منه، فيمكننا استخدام الطريقة المضمنة Object.entries(obj) التي تُرجع مصفوفة من أزواج المفاتيح/القيم لكائن بهذا التنسيق بالضبط.
حتى نتمكن من إنشاء خريطة من كائن مثل هذا:
دع الكائن = { الاسم: "جون"، العمر: 30 }; Let Map = new Map(Object.entries(obj)); تنبيه(map.get('name')); // جون
هنا، يقوم Object.entries
بإرجاع مصفوفة أزواج المفتاح/القيمة: [ ["name","John"], ["age", 30] ]
. هذا ما تحتاجه Map
.
لقد رأينا للتو كيفية إنشاء Map
من كائن عادي باستخدام Object.entries(obj)
.
هناك طريقة Object.fromEntries
التي تقوم بالعكس: نظرًا لمصفوفة من أزواج [key, value]
، فإنها تنشئ كائنًا منها:
دع الأسعار = Object.fromEntries([ ["الموز"، 1]، ["برتقالي"، 2]، ["اللحوم"، 4] ]); // الأسعار الآن = { الموز: 1، البرتقال: 2، اللحم: 4 } تنبيه (الأسعار. برتقالي)؛ // 2
يمكننا استخدام Object.fromEntries
للحصول على كائن عادي من Map
.
على سبيل المثال، نقوم بتخزين البيانات في Map
، ولكننا نحتاج إلى تمريرها إلى رمز جهة خارجية يتوقع كائنًا عاديًا.
ها نحن:
دع الخريطة = خريطة جديدة ()؛ Map.set('banana', 1); Map.set('برتقالي', 2); Map.set('اللحوم', 4); Let obj = Object.fromEntries(map.entries()); // اصنع كائنًا عاديًا (*) // منتهي! // obj = { موزة: 1، برتقالة: 2، لحم: 4 } تنبيه (obj.orange)؛ // 2
يُرجع استدعاء map.entries()
زوجًا متكررًا من المفاتيح/القيمات، بالتنسيق الصحيح تمامًا لـ Object.fromEntries
.
يمكننا أيضًا جعل السطر (*)
أقصر:
Let obj = Object.fromEntries(map); // حذف .الإدخالات ()
وهذا هو نفسه، لأن Object.fromEntries
يتوقع كائنًا قابلاً للتكرار كوسيطة. ليس بالضرورة مصفوفة. ويعيد التكرار القياسي map
نفس أزواج المفاتيح/القيمة مثل map.entries()
. لذلك نحصل على كائن عادي له نفس المفتاح/القيم مثل map
.
Set
عبارة عن مجموعة من النوع الخاص - "مجموعة القيم" (بدون مفاتيح)، حيث يمكن أن تحدث كل قيمة مرة واحدة فقط.
وأهم طرقها هي:
new Set([iterable])
- تنشئ المجموعة، وإذا تم توفير كائن iterable
(عادةً مصفوفة)، فسيتم نسخ القيم منه إلى المجموعة.
set.add(value)
- يضيف قيمة ويعيد المجموعة نفسها.
set.delete(value)
- يزيل القيمة، ويعيد القيمة true
إذا كانت value
موجودة في لحظة الاستدعاء، وإلا فإنها false
.
set.has(value)
- تُرجع true
إذا كانت القيمة موجودة في المجموعة، وإلا فإنها false
.
set.clear()
- يزيل كل شيء من المجموعة.
set.size
- هو عدد العناصر.
الميزة الرئيسية هي أن الاستدعاءات المتكررة لـ set.add(value)
بنفس القيمة لا تفعل أي شيء. وهذا هو سبب ظهور كل قيمة في Set
مرة واحدة فقط.
على سبيل المثال، لدينا زوار قادمون، ونود أن نتذكر الجميع. لكن الزيارات المتكررة لا ينبغي أن تؤدي إلى تكرارات. يجب أن يتم "احتساب" الزائر مرة واحدة فقط.
Set
هو الشيء الصحيح لذلك:
Let set = new Set(); دع جون = { الاسم: "جون" }; دع بيت = { الاسم: "بيت" }; دع ماري = { الاسم: "مريم" }; // الزيارات، يأتي بعض المستخدمين عدة مرات set.add(john); set.add(بيت); set.add(ماري); set.add(john); set.add(ماري); // تحتفظ المجموعة بالقيم الفريدة فقط تنبيه(set.size); // 3 لـ (السماح لمستخدم المجموعة) { تنبيه (اسم المستخدم) ؛ // جون (ثم بيت وماري) }
يمكن أن يكون البديل لـ Set
هو مجموعة من المستخدمين، والتعليمة البرمجية للتحقق من التكرارات في كل عملية إدراج باستخدام arr.find. لكن الأداء سيكون أسوأ بكثير، لأن هذه الطريقة تمر عبر المصفوفة بأكملها لفحص كل عنصر. تم تحسين Set
بشكل أفضل داخليًا للتحقق من التفرد.
يمكننا تكرار مجموعة إما باستخدام for..of
أو باستخدام forEach
:
Let set = new Set(["oranges"، "apples"، "bananas"]); for (اسمحوا قيمة المجموعة) تنبيه(قيمة); // نفس الشيء مع forEach: set.forEach((القيمة، valueAgain، مجموعة) => { تنبيه (قيمة)؛ });
لاحظ الشيء المضحك. تحتوي وظيفة رد الاتصال التي تم تمريرها في forEach
على ثلاث وسائط: value
، ثم نفس القيمة valueAgain
، ثم الكائن الهدف. في الواقع، تظهر نفس القيمة في الوسيطات مرتين.
هذا من أجل التوافق مع Map
حيث يحتوي رد الاتصال الذي تم تمريره forEach
على ثلاث وسائط. يبدو غريبا بعض الشيء، بالتأكيد. لكن هذا قد يساعد على استبدال Map
بـ Set
في حالات معينة بكل سهولة، والعكس صحيح.
يتم أيضًا دعم نفس الأساليب التي تستخدمها Map
للمكررات:
set.keys()
- إرجاع كائن قابل للتكرار للقيم،
set.values()
- نفس set.keys()
للتوافق مع Map
،
set.entries()
- يُرجع كائنًا قابلاً للتكرار للإدخالات [value, value]
، وهو موجود للتوافق مع Map
.
Map
- عبارة عن مجموعة من القيم ذات المفاتيح.
الطرق والخصائص:
new Map([iterable])
- تُنشئ الخريطة، مع iterable
اختياري (على سبيل المثال، صفيف) من أزواج [key,value]
للتهيئة.
map.set(key, value)
- يخزن القيمة بالمفتاح ويعيد الخريطة نفسها.
map.get(key)
- يُرجع القيمة حسب المفتاح، undefined
في حالة عدم وجود key
في الخريطة.
map.has(key)
- يُرجع true
في حالة وجود key
، false
في حالة عدم ذلك.
map.delete(key)
- يزيل العنصر بواسطة المفتاح، ويعيد true
إذا كان key
موجودًا في لحظة الاستدعاء، وإلا فهو false
.
map.clear()
- يزيل كل شيء من الخريطة.
map.size
- يُرجع عدد العناصر الحالي.
الاختلافات عن Object
عادي:
أي مفاتيح، يمكن أن تكون الكائنات مفاتيح.
طرق مريحة إضافية، خاصية size
.
Set
- عبارة عن مجموعة من القيم الفريدة.
الطرق والخصائص:
new Set([iterable])
- ينشئ المجموعة، مع قيم iterable
اختيارية (على سبيل المثال، صفيف) للتهيئة.
set.add(value)
- يضيف قيمة (لا يفعل شيئًا إذا كانت value
موجودة)، ويعيد المجموعة نفسها.
set.delete(value)
- يزيل القيمة، ويعيد القيمة true
إذا كانت value
موجودة في لحظة الاستدعاء، وإلا فإنها false
.
set.has(value)
- تُرجع true
إذا كانت القيمة موجودة في المجموعة، وإلا فإنها false
.
set.clear()
- يزيل كل شيء من المجموعة.
set.size
- هو عدد العناصر.
يكون التكرار عبر Map
و Set
دائمًا بترتيب الإدراج، لذلك لا يمكننا القول أن هذه المجموعات غير مرتبة، لكن لا يمكننا إعادة ترتيب العناصر أو الحصول على عنصر مباشرةً برقمه.
الأهمية: 5
دع arr
يكون مصفوفة.
قم بإنشاء دالة unique(arr)
التي يجب أن تُرجع مصفوفة تحتوي على عناصر فريدة من arr
.
على سبيل المثال:
وظيفة فريدة (arr) { /* الكود الخاص بك */ } دع القيم = ["هير"، "كريشنا"، "هير"، "كريشنا"، "كريشنا"، "كريشنا"، "هير"، "هير"، ":-O" ]; تنبيه (فريد (قيم))؛ // هير، كريشنا، :-O
ملاحظة: يتم استخدام سلاسل PS هنا، ولكن يمكن أن تكون قيمًا من أي نوع.
PPS استخدم Set
لتخزين القيم الفريدة.
افتح صندوق الرمل مع الاختبارات.
وظيفة فريدة (arr) { return Array.from(new Set(arr)); }
افتح الحل بالاختبارات في وضع الحماية.
الأهمية: 4
الجناس الناقص هي الكلمات التي تحتوي على نفس عدد الحروف نفسها، ولكن بترتيب مختلف.
على سبيل المثال:
قيلولة - مقلاة الأذن - هي - العصر الغشاشين - هكتار - المعلمين
اكتب دالة aclean(arr)
تُرجع مصفوفة تم تنظيفها من الجناس الناقصة.
على سبيل المثال:
Let arr = ["قيلولة"، "المعلمون"، "الغشاشون"، "PAN"، "الأذن"، "عصر"، "هكتار"]؛ تنبيه(نظيف(arr)); // "قيلولة، المعلمون، الأذن" أو "PAN، الغشاشون، عصر"
من كل مجموعة الجناس الناقص يجب أن تبقى كلمة واحدة فقط، بغض النظر عن أي منها.
افتح صندوق الرمل مع الاختبارات.
للعثور على جميع الجناس، دعونا نقسم كل كلمة إلى أحرف ونرتبها. عند فرز الحروف، تكون جميع الجناس متماثلة.
على سبيل المثال:
قيلولة، عموم -> Anp الأذن، العصر، هي -> إير الغشاشين، هكتار، المعلمين -> aceehrst ...
سنستخدم المتغيرات مرتبة بالأحرف كمفاتيح خريطة لتخزين قيمة واحدة فقط لكل مفتاح:
وظيفة نظيفة (آر) { دع الخريطة = خريطة جديدة ()؛ لـ (دع كلمة آر) { // قسّم الكلمة إلى حروف، ثم قم بفرزها ثم ضمها مرة أخرى دع فرزها = word.toLowerCase().split('').sort().join(''); // (*) Map.set(sorted, word); } return Array.from(map.values()); } Let arr = ["قيلولة"، "المعلمون"، "الغشاشون"، "PAN"، "الأذن"، "عصر"، "هكتار"]؛ تنبيه(نظيف(arr));
يتم فرز الحروف من خلال سلسلة المكالمات في السطر (*)
.
للراحة، دعونا نقسمها إلى عدة أسطر:
دعونا فرزها = كلمة // PAN .toLowerCase() // عموم .split('') // ['p','a','n'] .sort() // ['a','n','p'] .ينضم('')؛ // آنب
هناك كلمتان مختلفتان 'PAN'
و 'nap'
لهما نفس الشكل المرتب بالأحرف 'anp'
.
السطر التالي يضع الكلمة في الخريطة:
Map.set(sorted, word);
إذا التقينا بكلمة بنفس الشكل المرتب بالأحرف مرة أخرى، فسوف يتم استبدال القيمة السابقة بنفس المفتاح في الخريطة. لذلك سيكون لدينا دائمًا كلمة واحدة كحد أقصى لكل شكل حرف.
في النهاية، يأخذ Array.from(map.values())
كائنًا قابلاً للتكرار على قيم الخريطة (لا نحتاج إلى مفاتيح في النتيجة) ويعيد مصفوفة منها.
يمكننا هنا أيضًا استخدام كائن عادي بدلًا من Map
، لأن المفاتيح عبارة عن سلاسل.
هكذا يمكن أن يبدو الحل:
وظيفة نظيفة (آر) { دع obj = {}; لـ (دع i = 0; i < arr.length; i++) { Letsorted = arr[i].toLowerCase().split("").sort().join(""); obj[sorted] = arr[i]; } إرجاع Object.values(obj); } Let arr = ["قيلولة"، "المعلمون"، "الغشاشون"، "PAN"، "الأذن"، "عصر"، "هكتار"]؛ تنبيه(نظيف(arr));
افتح الحل بالاختبارات في وضع الحماية.
الأهمية: 5
نرغب في الحصول على مصفوفة من map.keys()
في متغير ثم تطبيق أساليب خاصة بالمصفوفة عليها، على سبيل المثال .push
.
لكن هذا لا ينجح:
دع الخريطة = خريطة جديدة ()؛ Map.set("name", "John"); دع المفاتيح = Map.keys(); // خطأ: key.push ليس دالة key.push("المزيد");
لماذا؟ كيف يمكننا إصلاح الكود حتى يعمل keys.push
؟
وذلك لأن map.keys()
تُرجع كائنًا قابلاً للتكرار، وليس مصفوفة.
يمكننا تحويله إلى مصفوفة باستخدام Array.from
:
دع الخريطة = خريطة جديدة ()؛ Map.set("name", "John"); دع المفاتيح = Array.from(map.keys()); key.push("المزيد"); تنبيه (مفاتيح)؛ // الاسم، المزيد