بازگشت به دوره

مجموعه ها (Sets)

در این بخش نیز قصد داریم با نوع داده‌ی دیگری در جاوا اسکریپت به نام مجموعه یا Set آشنا شویم. مجموعه‌ها در جاوا اسکریپت، شباهت زیادی به مجموعه‌ها در ریاضیات دارند. در واقع یک مجموعه نیز مانند یک آرایه می‌تواند تعدادی عضو داشته باشد. اما تفاوت مهم بین مجموعه‌ها و آرایه‌ها در این است که در یک آرایه می‌توان از عناصری با مقدار یکسان یا تکراری استفاده کرد. ولی در مجموعه‌ها هر مقدار فقط یک بار می‌تواند در مجموعه وجود داشته باشد و امکان تکرار وجود ندارد.

جهت ایجاد یک مجموعه‌ی جدید باید از تابع سازنده‌ی Set و عملگر new به شکل زیر استفاده کنیم.


let list = new Set();

جهت افزودن یک عضو جدید به مجموعه‌ی فوق باید از متد add به شکل زیر استفاده کرد.


list.add(1);
← Set {1}

همچنین می‌توان متد add را به صورت زنجیره‌ای به کار برد و چندین مقدار را با یک دستور به مجموعه اضافه کرد. در قطعه کد زیر ۳ عضو جدید به مجموعه‌ی list با یک دستور اضافه می‌شوند.


list.add(2).add(3).add(4);
← Set {1 , 2 , 3 , 4}

همانطور که اشاره شد، امکان قرار دادن دو عضو با مقدار یکسان در مجموعه‌ها وجود ندارد. بنابراین دستور زیر هیچ تغییری در مجموعه‌ی فوق ایجاد نمی‌کند. زیرا مقدار 1 از قبل در این مجموعه وجود دارد.


list.add(1);
← Set {1 , 2 , 3 , 4}

همچنین می‌توان در زمان ایجاد یک مجموعه، اعضای آن را نیز ایجاد کرد. برای این منظور باید اعضای مجموعه را به صورت یک آرایه به تابع Set ارسال کنیم. البته در این حالت نیز، باز هم می‌توان با استفاده از متد add اعضای جدیدی را به مجموعه اضافه کرد.


let list = new Set([1 , 2 , 2 , 3 , 3 , 4]);
list;
← Set {1 , 2 , 3 , 4}

همانطور که مشاهده می‌کنید، با توجه به اینکه مجموعه‌ها نمی‌توانند اعضای تکراری داشته باشند. عناصر تکراری موجود در آرایه‌ی اولیه فقط یک بار در مجموعه‌ی جدید ظاهر می‌شوند. همچنین اگر یک رشته را به عنوان ورودی تابع Set مشخص کنیم. هر یک از کاراکترهای رشته‌ی مذکور به عنوان یک عضو از مجموعه‌ی جدید در نظر گرفته می‌شوند و در این حالت نیز کاراکترهای تکراری حذف خواهند شد. به قطعه کد زیر توجه کنید.


let list = new Set('Hello');
list;
← Set {"H", "e", "l", "o"}

در صورتی که بخواهیم یک رشته را به طور کامل به عنوان یک عضو از مجموعه تعریف کنیم. باید رشته را به عنوان یک عنصر از آرایه به تابع Set ارسال کنیم. در این حالت می‌توان چند رشته‌ی مجزا را به صورت عناصر یک آرایه به تابع Set ارسال کرد تا هر یک از رشته‌ها به عنوان یک عضو مجموعه‌ی جدید در نظر گرفته شوند. به قطعه کد زیر توجه کنید.


let list = new Set(['Apple' , 'Orange' , 'Banana']);
list;
← Set {"Apple", "Orange", "Banana"}

توجه کنید که در مجموعه‌ها برای تشخیص تکراری بودن اعضاء، هیچ تبدیل نوعی انجام نمی‌شود. در نتیجه یک مقدار عددی با مقدار رشته‌ای معادلش یکسان نیستند و می‌توانند همزمان در یک مجموعه حضور داشته باشند. مثلاً در قطعه کد زیر عدد 2 و کاراکتر "2" در یک مجموعه قرار می‌گیرند و تکراری محسوب نمی‌شوند.


let list = new Set(['2' , 2]);
list;
← Set {"2", 2}

نکته‌ی بسیار مهم دیگر این است که انواع داده‌ی غیر اولیه (non-primitive) مانند آرایه‌ها، حتی در صورتی که مقدار داده‌هایشان یکسان باشد، با هم برابر نیستند و می‌توانند همزمان در یک مجموعه حضور داشته باشند. یعنی تکراری بودن اعضاء، فقط برای داده‌های اولیه (primitive) در نظر گرفته می‌شود. به عنوان مثال در قطعه کد زیر دو آرایه با داده‌های کاملاً یکسان در یک مجموعه قرار می‌گیرند.


let list = new Set([[1] , [1]]);
list;
← Set {[1] , [1]}

دلیل رفتار فوق این است که انواع داده‌ی غیر اولیه (مانند آرایه‌ها) در زمان مقایسه، مقدار داده‌هایشان با هم مقایسه نمی‌شود. بلکه مقدار اشاره‌گر آنها (آدرسشان در حافظه) با هم مقایسه می‌شود. به همین دلیل دستور زیر که دو آرایه با عناصر کاملاً یکسان را با هم مقایسه می‌کند، مقدار false تولید می‌کند. زیرا اشاره‌گر این دو آرایه با هم متفاوت است. (در مورد اشاره‌گرها و انواع ارجاع در فصل ۴ بیشتر صحبت خواهیم کرد.)


[1] == [1]
← false
 

متدها و خواص مجموعه‌ها

با استفاده از خاصیت size می‌توان تعداد اعضای یک مجموعه را به دست آورد. به قطعه کد زیر توجه کنید.


let list = new Set(['Apple' , 'Orange' , 'Banana']);
list.size;
← 3

با استفاده از متد has می‌توان بررسی کرد که آیا یک عضو خاص در اعضای یک مجموعه وجود دارد یا خیر؟ این متد در واقع همان کاری را می‌کند که متد includes در آرایه‌ها انجام می‌داد. اما سرعت اجرای متد has از متد includes بیشتر است.


let list = new Set(['Apple' , 'Orange' , 'Banana']);
list.has('Apple');
← true
list.has('Cherry');
← false
توجه کنید که برای دسترسی به اعضای مجموعه‌ها نمی‌توان از اندیس (مثلاً list[0]) استفاده کرد.

با استفاده از متد delete نیز می‌توان یک عضو خاص را از مجموعه حذف کرد. در صورتی که عضو مورد نظر در مجموعه وجود داشته باشد، پس از حذف آن عضو، مقدار true و در صورت عدم وجود عضو مورد نظر، مقدار false بازگردانده می‌شود.


let list = new Set(['Apple' , 'Orange' , 'Banana']);
list.delete('Apple');
← true
list.delete('Cherry');
← false

با استفاده از متد clear نیز می‌توان کل اعضای یک مجموعه را حذف کرد.


let list = new Set(['Apple' , 'Orange' , 'Banana']);
list.clear();
list;
← Set {}
list.size;
← 0
 

تبدیل مجموعه‌ها به آرایه

دو روش برای تبدیل یک مجموعه به آرایه وجود دارد. روش اول استفاده از عملگر spread است که باید داخل علامت "[ ]" به کار برده شود.


let fruitsSet = new Set(['Apple' , 'Orange' , 'Banana']);
fruitsSet;
← Set {"Apple" , "Orange" , "Banana"}
let fruitsArray = [...fruitsSet];
fruitsArray;
← ["Apple" , "Orange" , "Banana"]

روش دوم تبدیل یک مجموعه به آرایه، با استفاده از متد from از شئ Array است. قطعه کد زیر نحوه‌ی انجام این کار را نشان می‌دهد.


let fruitsSet = new Set(['Apple' , 'Orange' , 'Banana']);
let fruitsArray = Array.from(fruitsSet);
fruitsArray;
← ["Apple" , "Orange" , "Banana"]

با استفاده از هر یک از روش‌های فوق می‌توان در صورت نیاز، عناصر تکراری یک آرایه را حذف کرد. یعنی ابتدا آرایه‌ای که دارای عناصر تکراری است را به یک مجموعه تبدیل می‌کنیم تا عناصر تکراری آن حذف شوند. سپس مجموعه‌ی به دست آمده را با یکی از روش‌های فوق، دوباره به آرایه تبدیل می‌کنیم.


let duplicate = [3 , 1 , 4 , 1 , 5 , 9 , 2 , 6 , 5 , 3 , 5 , 9];
duplicate;
← [3 , 1 , 4 , 1 , 5 , 9 , 2 , 6 , 5 , 3 , 5 , 9]
let nonDuplicate = Array.from(new Set(duplicate));
nonDuplicate;
← [3 , 1 , 4 , 5 , 9 , 2 , 6]

همانطور که مشاهده می‌کنید آرایه‌ی nonDuplicate هیچ عنصر تکراری ندارد. این روش بسیار ساده در برخی موارد می‌تواند بسیار مفید واقع شود. لازم به ذکر است که در جاوا اسکریپت نوع دیگری از مجموعه‌ها نیز وجود دارد. این نوع از مجموعه‌ها به مجموعه‌های ضعیف (WeakSets) مشهور هستند. در رابطه با این نوع مجموعه‌ها و خواص آنها در فصل ۱۱ بیشتر صحبت خواهیم کرد.