Enum ماژولی بسیار کاربردی است که مجموعهای از الگوریتمها را برای کار با دادههای شمارشپذیر فراهم میکند. این ماژول مرتبسازی، فیلتر کردن، گروهبندی، شمارش، جستوجو، یافتن کمینه و بیشینه و موارد بسیار بیشتری را ارائه میدهد.
بهطور کلی، «شمارشپذیر» هر دادهای است که میتوان آن را پیمایش کرد، یعنی یک مجموعه. در Elixir، شمارشپذیر هر نوع دادهای است که پروتکل Enumerable را پیادهسازی کند. رایجترین آنها لیست و مپ هستند.
بسیاری از توابع Enum یک تابع را به عنوان آرگومان میپذیرند.
Enum.all?([1, 2, 3, 4, 5], fn x -> x > 3 end)
# => false
رایجترین توابع Enum، map و reduce هستند.
map/2Enum.map/2 به شما اجازه میدهد هر عنصر یک شمارشپذیر را با عنصری دیگر جایگزین کنید. آرگومان دوم Enum.map/2 تابعی است که عنصر اصلی را میپذیرد و جایگزین آن را برمیگرداند.
reduce/3Enum.reduce/3 به شما اجازه میدهد کل شمارشپذیر را به یک مقدار واحد کاهش دهید. برای این کار، متغیری ویژه به اسم «انباشتگر» به کار میرود. انباشتگر وضعیت میانی کاهش را بین تکرارها نگه میدارد.
آرگومان دوم Enum.reduce/3 مقدار اولیهی انباشتگر است. آرگومان سوم تابعی است که یک عنصر و یک انباشتگر را میپذیرد و مقدار جدید انباشتگر را برمیگرداند.
وقتی از مپها همراه با توابع Enum استفاده میکنید، مپ بهطور خودکار به لیستی از ۲ تاپل {key, value} تبدیل میشود.
برای تبدیل دوبارهی آن به یک مپ، از Enum.into/2 استفاده کنید. Enum.into/2 تابعی است که یک شمارشپذیر را به یک «جمعشدنی» تبدیل میکند، یعنی هر ساختار دادهای که پروتکل Collectable را پیادهسازی کند. میتوان آن را معکوس Enum.reduce/3 در نظر گرفت.
Enum همچنین Enum.into/3 را دارد. Enum.into/3 گونهای از Enum.into/2 است که یک تابع تبدیل میپذیرد تا هنگام تبدیل شمارشپذیر به جمعشدنی اعمال شود.
بهجای استفاده از Enum.into/3 یا Enum.map/2 بههمراه Enum.into/2 برای اعمال یک تبدیل (مپ کردن) روی یک مپ، میتوانیم از تابع اختصاصی Map.new/2 هم استفاده کنیم. این تابع دقیقاً مثل Enum.into/3 کار میکند، یعنی یک شمارشپذیر و یک تابع تبدیل میپذیرد، اما همیشه یک مپ جدید برمیگرداند و اجازه نمیدهد خودمان جمعشدنی را انتخاب کنیم.
شما یک بوتیک مد آنلاین را اداره میکنید. حراج بزرگ سالانهتان نزدیک است، پس باید موجودی خود را بررسی کنید تا مطمئن شوید آمادهاید.
هر کالا در موجودی با یک نگاشت نشان داده میشود و کل موجودی فهرستی از همین نگاشتهاست.
%{
name: "White Shirt",
price: 40,
quantity_by_size: %{s: 3, m: 7, l: 8, xl: 4}
}
تابع sort_by_price/1 را پیادهسازی کنید. این تابع باید موجودی را بگیرد و آن را بر اساس قیمت کالاها به ترتیب صعودی برگرداند.
BoutiqueInventory.sort_by_price([
%{price: 65, name: "Maxi Brown Dress", quantity_by_size: %{}},
%{price: 50, name: "Red Short Skirt", quantity_by_size: %{}},
%{price: 50, name: "Black Short Skirt", quantity_by_size: %{}},
%{price: 20, name: "Bamboo Socks Cats", quantity_by_size: %{}}
])
# => [
# %{price: 20, name: "Bamboo Socks Cats", quantity_by_size: %{}},
# %{price: 50, name: "Red Short Skirt", quantity_by_size: %{}},
# %{price: 50, name: "Black Short Skirt", quantity_by_size: %{}},
# %{price: 65, name: "Maxi Brown Dress", price: 65, quantity_by_size: %{}}
# ]
پس از مرتبسازی موجودی بر اساس قیمت، متوجه شدید که حتماً هنگام بررسی موجودی اشتباه کردهاید و فراموش کردهاید قیمت چند کالا را ثبت کنید.
تابع with_missing_price/1 را پیادهسازی کنید. این تابع باید موجودی را بگیرد و کالاهایی را که قیمت ندارند بهصورت فهرست برگرداند.
BoutiqueInventory.with_missing_price([
%{price: 40, name: "Black T-shirt", quantity_by_size: %{}},
%{price: nil, name: "Denim Pants", quantity_by_size: %{}},
%{price: nil, name: "Denim Skirt", quantity_by_size: %{}},
%{price: 40, name: "Orange T-shirt", quantity_by_size: %{}}
])
# => [
# %{price: nil, name: "Denim Pants", quantity_by_size: %{}},
# %{price: nil, name: "Denim Skirt", quantity_by_size: %{}}
# ]
متوجه شدید که در اسم بعضی کالاها کلمهای وجود دارد که دیگر نمیخواهید از آن استفاده کنید. حالا باید همهی اسمهای کالاها را که آن کلمه را دارند بهروزرسانی کنید.
تابع update_names/3 را پیادهسازی کنید. این تابع باید موجودی، کلمهی قدیمیای را که میخواهید حذف کنید و کلمهی جدیدی را که میخواهید بهجایش استفاده کنید بگیرد. باید فهرستی از کالاها را با اسمهای بهروزرسانیشده برگرداند.
BoutiqueInventory.update_names(
[
%{price: 40, name: "Black T-shirt", quantity_by_size: %{}},
%{price: 70, name: "Denim Pants", quantity_by_size: %{}},
%{price: 65, name: "Denim Skirt", quantity_by_size: %{}},
%{price: 40, name: "Orange T-shirt", quantity_by_size: %{}}
],
"T-shirt",
"Tee"
)
# => [
# %{price: 40, name: "Black Tee", quantity_by_size: %{}},
# %{price: 70, name: "Denim Pants", quantity_by_size: %{}},
# %{price: 65, name: "Denim Skirt", quantity_by_size: %{}},
# %{price: 40, name: "Orange Tee", quantity_by_size: %{}}
# ]
بعضی کالاها بهطور ویژه خوب فروش میرفتند، برای همین در همهی سایزها بیشتر سفارش دادید.
تابع increase_quantity/2 را پیادهسازی کنید. این تابع باید یک کالا و یک عدد n بگیرد و همان کالا را برگرداند با این تفاوت که تعداد هر سایز به اندازهی n افزایش یافته باشد.
BoutiqueInventory.increase_quantity(
%{
name: "Polka Dot Skirt",
price: 68,
quantity_by_size: %{s: 3, m: 5, l: 3, xl: 4}
},
6
)
# => %{
# name: "Polka Dot Skirt",
# price: 68,
# quantity_by_size: %{l: 9, m: 11, s: 9, xl: 10}
# }
برای اینکه بدانید در انبارتان چقدر فضا نیاز دارید، باید بدانید از هر کالا در کل چند عدد دارید.
تابع total_quantity/1 را پیادهسازی کنید. این تابع باید یک کالا بگیرد و تعداد کل آن را برگرداند؛ یعنی در هر سایزی، در کل چند عدد دارید.
BoutiqueInventory.total_quantity(%{
name: "Red Shirt",
price: 62,
quantity_by_size: %{s: 3, m: 6, l: 5, xl: 2}
})
# => 16