در این مقاله قصد داریم تا به بررسی چند روش متفاوت به منظور حذف یکسری آیتم تکراری از میان اِلِمانهای یک آرایه در زبان برنامهنویسی جاوااسکریپت بپردازیم به طوری که در نهایت یک آرایه با اِلِمانهای منحصربهفرد داشته باشیم (جهت آشنایی با مفهوم آرایه و کاربردهای آن در زبان برنامهنویسی جاوااسکریپت توصیه میکنیم به مقالۀ آشنایی با مفهوم آرایه و روشهای ساخت آن مراجعه نمایید.)
بهکارگیری آبجکت Set
یکی از روشهای بسیار ساده و رایج به منظور حذف آیتمهای تکراری از میان اِلِمانهای یک آرایه بهکارگیری آبجکت Set
است. در واقع، کیورد Set
در نسخۀ ES6 از این زبان معرفی شده و به منظور ساخت آبجکتهای جدیدی مورد استفاده قرار میگیرد که با بهکارگیری آنها میتوان یکسری مقدار منحصربهفرد با انواع مختلف را ذخیره و نگهداری کرد.
در همین راستا، ابتدا یک آبجکت جدید از نوع Set
ساخته و آرایۀ مد نظر خود را به عنوان آرگومان ورودی به آن میدهیم و همانطور که اشاره کردیم، این آبجکت صرفاً مقادیر منحصربهفرد را شامل میشود که از داخل آن تمامی اِلِمانهای تکراری از آرایۀ مذکور حذف میشوند و در گام بعدی آبجکت حاصله را مجدداً به آبجکتی از جنس آرایه تبدیل میکنیم که برای این منظور نیز اپراتور ...
را مورد استفاده قرار میدهیم که اصطلاحاً Spread نامیده میشود (جهت آشنایی با سایر اپراتورها در این زبان میتوانید به مقالۀ درآمدی بر اپراتورها در جاوااسکریپت مراجعه کنید.)
حال با توجه به آنچه گفته شد، کد زیر را به منظور حذف اِلِمانهای تکراری از یک آرایۀ دلخواه و با بهکارگیری آبجکتی از نوع Set
مد نظر قرار میدهیم:
const array = ['a', 1, 2, 'a', 'a', 3];
const uniqueSet = new Set(array);
const backToArray = [...uniqueSet];
در کد فوق، ابتدا آرایهای متشکل از اِلِمانهای مختلف تعریف کرده و آن را به متغیری تحت عنوان array
منتسب کردهایم و در ادامه آبجکت جدیدی از نوع Set
ساخته و آرایۀ فوقالذکر را به عنوان آرگومان ورودی به آن دادهایم؛ بدین ترتیب آبجکت Set
آیتمهای تکراری در آرایۀ مد نظر را حذف کرده و خروجی را در متغیری تحت عنوان uniqueSet
نگهداری میکند. از این پس آبجکتی از نوع Set
و متشکل از چند اِلِمان منحصربهفرد داریم که در سطر بعد با بهکارگیری اپراتور ...
نوع آن را به آرایه تغییر داده و نتیجه را در متغیری به نام backToArray
ذخیره کردهایم که خروجی حاصل از کد فوق بدین ترتیب خواهد بود:
['a', 1, 2, 3]
همانطور که میبینید، آرایهای متشکل از اِلِمانهای منحصربهفرد داریم. همچنین به منظور تبدیل آبجکت Set
به آبجکتی از جنس آرایه نیز میتوان متد از پیش تعریفشدۀ ()Array.from
را مورد استفاده قرار داد که هر یک از اِلِمانهای آرگومان ورودی را به آبجکتی از جنس آرایه تبدیل میکند که برای این منظور کد مثال قبل را بدین صورت تغییر میدهیم:
const array = ['a', 1, 2, 'a', 'a', 3];
Array.from(new Set(array));
در کد فوق، آرایهای متشکل از چند اِلِمان مختلف تعریف کرده و آن را به متغیری تحت عنوان array
منتسب کردهایم و در ادامه با بهکارگیری کیورد new
آبجکتی از نوع Set
ساخته و آرایهٔ تعریفشده را به عنوان آرگومان ورودی به آن دادهایم که منجر بدین میشود تا اِلِمانهای تکراری از آرایۀ مد نظر حذف شوند که در ادامه آبجکتی از نوع Set
و متشکل از چند اِلِمان منحصربهفرد داریم که خروجی حاصل از آن را به متد ()Array.from
میدهیم تا در نهایت آرایهای از اِلِمانهای غیرتکراری و منحصربهفرد داشته باشیم. خروجی حاصل از کد فوق بدین ترتیب خواهد بود:
['a', 1, 2, 3]
همانطور که ملاحظه میکنید، در این مورد نیز نتیجۀ حاصل آبجکتی از جنس آرایه و متشکل از اِلِمانهای منحصربهفرد میباشد.
استفاده از متد ()filter
در این روش از متدهای به اصطلاح Built-in تحت عناوین ()indexOf
و ()filter
استفاده خواهیم کرد. در همین راستا، ابتدا نیاز است تا نحوۀ عملکرد متد ()indexOf
را تشریح کنیم. در واقع، این متد بدین صورت عمل میکند که یک آرگومان ورودی گرفته و در آرایۀ مربوطه به دنبال اندیس آن میگردد و در ادامه اندیس مربوط به اولین اِلِمان پیداشده را در خروجی ریترن میکند که برای درک بهتر نحوۀ کار این متد مثال زیر را در ادامه آوردهایم:
const array = ['a', 1, 2, 'a', 'a', 3];
array.indexOf('a');
در کد فوق، آبجکتی از جنس آرایه و متشکل از چند اِلِمان دلخواه تعریف کرده و آن را به متغیری به نام array
منتسب کردهایم و در سطر بعد متد ()indexOf
را روی این آبجکت فراخوانی کرده و گفتهایم که اندیس مربوط به اولین اِلِمان با مقداری معادل استرینگ «a» داخل آرایه را در خروجی ریترن کند که در خروجی خواهیم داشت:
0
همانطور که انتظار داشتیم، اولین اِلِمان با مقداری معادل استرینگ «a» در آرایۀ فوق به خانۀ شمارۀ صفرم تعلق دارد و عدد صفر در معرض دید ما قرار گرفته است.
حال به تشریح نحوۀ عملکرد متد ()filter
میپردازیم. در واقع، این متد آرایهای جدید ساخته و اِلِمانهایی از آرایۀ اصلی که با شرایط تعریفشده مطابقت داشته باشند را در آن نگهداری میکند؛ به عبارت دیگر، این متد هر یک از اِلِمانهای آرایه را به عنوان ورودی گرفته و هر یک را چک میکند تا در نهایت اِلِمانهایی را به آرایۀ جدید اضافه کند که با شرایط تعیینشده مطابقت دارند. در ادامه متد ()filter
را به منظور حذف اِلِمانهای تکراری از آرایۀ مثال قبل بدین صورت پیادهسازی میکنیم:
const array = ['a', 1, 2, 'a', 'a', 'a', 3];
array.filter((item, index) => {
console.log(item, index, array.indexOf(item), array.indexOf(item) === index, );
return array.indexOf(item) === index
});
در کد فوق، آبجکتی از جنس آرایه ایجاد کرده و چند اِلِمان مختلف به آن اختصاص میدهیم و در ادامه متدی به نام ()filter
ساختهایم که در آن دو پارامتر ورودی تحت عناوین item
و index
تعریف کردهایم که به ترتیب به منظور نگهداری مقدار هر یک از اِلِمانهای آرایه و اندیس مربوط به آنها مورد استفاده قرار میگیرند و در سطر بعد گفتهایم به ترتیب مقادیر هر یک از اِلِمانهای آرایه، اندیس مربوط به هر اِلِمان، اندیس مربوط به اولین مقدار مشاهدهشده از اِلِمان مد نظر در آرایه و در نهایت مقدار بولین مربوط به مقایسۀ دو پارامتر دوم و سوم را در خروجی چاپ کند؛ به عبارت دیگر، پارامتر ورودی چهارم در صورتی مقدار true
میگیرد که تنها یک مقدار از اِلِمانهای مد نظر در آرایۀ اصلی داشته باشیم به طوری که اندیس مربوط به اِلِمان مد نظر برابر با اندیس اولین مقدار مشاهدهشده از آن در آرایۀ فوقالذکر باشد. در سطر آخر نیز گفتهایم مقادیر هر یک از اِلِمانهایی که مقدار بولین مربوط به آنها برابر با true
است را در خروجی ریترن کند که خروجی حاصل از این کد را در قالب جدولی به صورت زیر آوردهایم:
Condition | indexOf | Index | Item |
true | 0 | 0 | a |
true | 1 | 1 | 1 |
true | 2 | 2 | 2 |
false | 0 | 3 | a |
false | 0 | 4 | a |
false | 0 | 5 | a |
true | 3 | 6 | 6 |
در نهایت، بر اساس آنچه در بالا توضیح دادیم، آرایهای در خروجی داریم که مقدار بولین مربوط به اِلِمانهای آن برابر با true
است:
['a', 1, 2, 3]
همانطور که میبینید، آرایهای جدید با اِلِمانهای منحصربهفرد داریم که مقادیر تکراری متعلق به آرایۀ اصلی از آن حذف شدهاند.
نحوۀ دستیابی به اِلِمانهای تکراری آرایه
همچنین برای دستیابی به اِلِمانهای تکراری آرایه میتوانیم متد ()filter
را مورد استفاده قرار دهیم که برای این منظور نیاز است تا شرط تعریفشده در مثال قبل را بدین صورت تغییر دهیم:
const array = ['a', 1, 2, 'a', 'a', 'a', 3];
array.filter((item, index) => {
console.log(item, index, array.indexOf(item), array.indexOf(item) !== index, );
return array.indexOf(item) !== index
});
نحوۀ عملکرد کد فوق نیز مشابه مثال قبل است با این تفاوت که در این مثال گفتهایم تمامی اِلِمانهایی را در خروجی ریترن کند که اندیس مربوط به آنها در آرایۀ اصلی با اندیس اولین مقدار مشاهدهشده از آن اِلِمان برابر نباشد که بدین ترتیب مقدار بولین پارامتر ورودی چهارم زمانی برابر با true
خواهد بود که اندیس اِلِمان مد نظر برابر با اندیس اولین مقدار پیداشده از این اِلِمان در آرایه نباشد؛ به عبارت دیگر، اِلِمانهایی در خروجی ریترن میشوند که در آرایۀ مد نظر تکراری هستند. به طور کلی، خروجی حاصل از اجرای کد فوق در جدول زیر ارائه شده است:
Condition | indexOf | Index | Item |
false | 0 | 0 | a |
false | 1 | 1 | 1 |
false | 2 | 2 | 2 |
true | 0 | 3 | a |
true | 0 | 4 | a |
true | 0 | 5 | a |
false | 3 | 6 | 6 |
در نهایت بر اساس آنچه در بالا توضیح دادیم، آرایهای در خروجی داریم که اندیس هر یک از آنها با اندیس اولین اِلِمان پیداشده از آیتمهای مذکور برابر نباشند:
['a', 'a', 'a']
همانطور که ملاحظه میشود، آرایهای جدید با اِلِمانهای تکراری داریم که مقادیر غیرتکراری متعلق به آرایۀ اصلی از آن حذف شدهاند.
بهکارگیری متد ()reduce
متد از پیش تعریفشدۀ ()reduce
برای کاستن تعداد اِلِمانهای آرایه استفاده میشود به طوری که یک آرایۀ جدید ساخته و بر اساس شرایط تعیینشده یکسری مقادیر مربوط به آرایۀ اصلی را حذف کرده و مابقی را در آن نگهداری میکند.
در مثال زیر، شرط تعیینشده به منظور حذف برخی اِلِمانهای مربوط به آرایۀ اصلی بدین صورت میباشد که یک اِلِمان از آرایۀ اصلی برداشته و در صورتی آن را به آرایۀ جدید اضافه میکند که آیتم مربوطه قبلاً در این آرایه وجود نداشته باشد؛ به عبارت بهتر، آیتمهای غیرتکراری به آرایۀ جدید افزوده میشوند و در صورت تکراری بودن اِلِمان مذکور آخرین مقادیر ذخیرهشده در آرایۀ جدید در خروجی ریترن میشود که به منظور پیادهسازی این فانکشن کدی مانند زیر خواهیم داشت:
const array = ['a', 1, 2, 'a', 'a', 3];
array.reduce((unique, item) => {
console.log(item, unique, unique.includes(item), unique.includes(item) ? unique : [...unique, item], );
return unique.includes(item) ? unique : [...unique, item]
}, []);
در کد فوق آبجکتی از جنس آرایه به نام array
ساخته و یکسری اِلِمان به آن اختصاص دادهایم و در سطر بعد فانکشن ()reduce
را با دو پارامتر ورودی تحت عناوین unique
و item
فراخوانی کردهایم که در آن گفتهایم به ترتیب مقادیر زیر را در خروجی ریترن کند:
- هر یک از اِلِمانهای آرایۀ اصلی
- آرایهای تحت عنوان unique
که متشکل از اِلِمانهای آرایهٔ اصلی پیش از حذف است (در واقع، اِلِمانهای آرایه اصلی را که تکبهتک از آن خارج کرده و به آرایۀ جدید اضافه میکند.)
- مقدار بولین مربوط به شرط مسئله که در آن گفتهایم چنانچه آیتم مد نظر از آرایۀ اصلی در آرایۀ جدیدِ unique
موجود بود، مقدار true
و در غیر این صورت مقدار false
را در خروجی ریترن کند.
- و آرایۀ نهایی با حذف مقادیر تکراری
در نهایت، خروجی حاصل از اجرای کد فوق به ترتیب زیر خواهد بود:
(Array (After Reducer Function | Push to Array | (Array (Before Reducer Function | Item |
['a'] | true | [ ] | a |
[a', 1'] | true | ['a'] | 1 |
[a', 1, 2'] | true | [a', 1'] | 2 |
[a', 1, 2'] | false | [a', 1, 2'] | a |
[a', 1, 2'] | false | [a', 1, 2'] | a |
[a', 1, 2, 3'] | true | [a', 1, 2'] | 3 |
همانطور که میبینید، ابتدا آیتم اول را از آرایۀ اصلی برداشته و چک میکنیم که آیا در آرایۀ منتسب به متغیر unique
مقداری معادل استرینگ «a» وجود دارد یا خیر که میبینیم آرایۀ unique
خالی بوده و از همین روی خروجی دستور شرطی true
میشود و اِلِمان مد نظر به آرایۀ جدید افزوده میشود. به همین ترتیب برای باقی اِلِمانها شرط تعیینشده چک میشود که اگر اِلِمان مد نظر تکراری باشد به آرایۀ جدید افزوده نمیشود که در چنین شرایطی آخرین مقادیر منتسب به آرایۀ جدید در خروجی ریترن میشود و در نهایت داریم:
['a', 1, 2, 3]
همانطور که میبینید، آرایهای جدید داریم که مقادیر تکراری مربوط به آرایۀ اصلی از آن حذف شدهاند.
جمعبندی
در این مقاله به بیان برخی از روشهای رایج جهت حذف اِلِمانهای تکراری از آرایهها در زبان جاوااسکریپت پرداختیم و نحوۀ پیادهسازی هر یک را در قالب مثالی کاربردی بررسی کردیم اما توجه داشته باشیم که روشهای بسیاری برای این منظور میتوان پیادهسازی کرد که متناسب با موقعیتهای مختلف به کار گرفته میشوند و نیازمند مطالعه، تمرین و تحقیق بیشتر هستند.