ساخت اندیس درون حافظه با جاوا اسکریپت — از صفر تا صد

۷۲ بازدید
آخرین به‌روزرسانی: ۰۷ شهریور ۱۴۰۲
زمان مطالعه: ۳ دقیقه
ساخت اندیس درون حافظه با جاوا اسکریپت — از صفر تا صد

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

فرض کنید می‌خواهید یک اپلیکیشن فروش آنلاین بسازید و به آرایه‌ای مانند زیر نیاز دارید:

1const skus = [
2  {
3    "productId": 1,
4    "colorId": 1,
5    "sku": "11-M"
6  },
7  {
8    "productId": 1,
9    "colorId": 1,
10    "sku": "11-L"
11  },
12  {
13    "productId": 1,
14    "colorId": 2,
15    "sku": "12-M"
16  },
17  {
18    "productId": 1,
19    "colorId": 2,
20    "sku": "12-L"
21  },
22  {
23    "productId": 2,
24    "colorId": 1,
25    "sku": "21-M"
26  },
27  {
28    "productId": 2,
29    "colorId": 1,
30    "sku": "21-L"
31  }
32];

با فرض آرایه فوق وظیفه شما این است که همه SKU-ها را برای یک productId خاص به دست آورید. نخستین چیزی که به ذهن می‌رسد، استفاده از کد زیر است:

1skus.find(s => productId === s.productId)

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

به این منظور از reduce استفاده می‌کنیم:

1const skus = [
2  {
3    "productId": 1,
4    "colorId": 1,
5    "sku": "11-M"
6  },
7  {
8    "productId": 1,
9    "colorId": 1,
10    "sku": "11-L"
11  },
12  {
13    "productId": 1,
14    "colorId": 2,
15    "sku": "12-M"
16  },
17  {
18    "productId": 1,
19    "colorId": 2,
20    "sku": "12-L"
21  },
22  {
23    "productId": 2,
24    "colorId": 1,
25    "sku": "21-M"
26  },
27  {
28    "productId": 2,
29    "colorId": 1,
30    "sku": "21-L"
31  }
32];

بنابراین کد به صورت زیر خواهد بود:

1const productIndex = indexByField(skus, “productId”);

اندیس نیز به صورت زیر درمی‌آید:

1{
2  "1": [
3    {
4      "productId": 1,
5      "colorId": 1,
6      "sku": "11-M"
7    },
8    {
9      "productId": 1,
10      "colorId": 1,
11      "sku": "11-L"
12    },
13    {
14      "productId": 1,
15      "colorId": 2,
16      "sku": "12-M"
17    },
18    {
19      "productId": 1,
20      "colorId": 2,
21      "sku": "12-L"
22    }
23  ],
24  "2": [
25    {
26      "productId": 2,
27      "colorId": 1,
28      "sku": "21-M"
29    },
30    {
31      "productId": 2,
32      "colorId": 1,
33      "sku": "21-L"
34    }
35  ]
36}

اینک می‌توانیم همه SKU-ها را برای یک محصول خاص به دست آوریم.

روش دستیابی به SKU-ها با رنگ خاص

همچنان که متوجه شدید در بخش قبل تنها آرایه خود را بر اساس productId اندیس گذاری کردیم، اما در این بخش آن را برحسب colorId نیز اندیس گذاری می‌کنیم.

با توجه به حالت اندیس جاری، روش اندیس گذاری مقادیر آن با استفاده از تابع indexByField خواهد بود. این تابع پاسخگو است، اما اگر سطوح اندیس گذاری زیاد شوند باید از «بازگشت» (Recursion) کمک بگیریم.

1const mapObjectValues = (value, shouldMap, mapFn, ...args) => {
2  if (shouldMap(value)) {
3    return mapFn(value, ...args);
4  }
5  return {
6    ...Object.keys(value).reduce(
7      (acc, k) => ({
8        ...acc,
9        [k]: mapObjectValues(value[k], shouldMap, mapFn, ...args),
10      }),
11      {},
12    ),
13  };
14};

در ادامه این mapObjectValues را به تفصیل توضیح می‌دهیم.

  • Value در نخستین فراخوانی آرایه ما خواهد بود و در فراخوانی بازگشتی بعدی ما اندیس می‌شود.
  • shouldMap تعیین می‌کند چه زمانی فراخوانی‌های بازگشتی را متوقف کنیم. در این مورد این مقدار Array.isArray است.
  • mapFn مقادیر اندیس را تبدیل می‌کند. این فرایند شبیه کاری است که Array.prototype.map روی آیتم‌های آرایه انجام می‌دهد. در این مورد از تابع indexByField استفاده می‌کنیم.

جمع‌بندی

اینک آماده هستیم تابع خود را برای اندیس گذاری یک آرایه برای چند فیلد بنویسیم. ضمناً Array.prototype را طوری بسط می‌دهیم که مستقیماً از وهله ما فراخوانی شود:

1const indexBy = (value, ...fields) => {	
2  if (fields.length === 0) {	
3    return value;	
4  }	
5  const [currentField, ...rest] = fields;	
6  const newValue = mapObjectValues(value, Array.isArray, indexByField, currentField);	
7  return indexBy(newValue, ...rest);	
8};	
9Array.prototype.indexBy = function(...fields) {	
10  return indexBy(this, ...fields);	
11};

اینک کد به صورت زیر درمی‌آید:

1const productColorIndex = skus.indexBy(“productId”, "colorId");

و مقدار آن نیز چنین است:

1{
2  "1": {
3    "1": [
4      {
5        "productId": 1,
6        "colorId": 1,
7        "sku": "11-M"
8      },
9      {
10        "productId": 1,
11        "colorId": 1,
12        "sku": "11-L"
13      }
14    ],
15    "2": [
16      {
17        "productId": 1,
18        "colorId": 2,
19        "sku": "12-M"
20      },
21      {
22        "productId": 1,
23        "colorId": 2,
24        "sku": "12-L"
25      }
26    ]
27  },
28  "2": {
29    "1": [
30      {
31        "productId": 2,
32        "colorId": 1,
33        "sku": "21-M"
34      },
35      {
36        "productId": 2,
37        "colorId": 1,
38        "sku": "21-L"
39      }
40    ]
41  }
42}

اینک می‌توانیم SKU-ها را صرفاً با محاسبه اندیس به دست آوریم:

1productColorIndex["1"]["2"];

سخن پایانی

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

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
itnext
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *