محمدرضا علاقهی زیادی به بهینه بودن برنامهها دارد. او که در زمینهی الگوریتم بسیار خفن است، میداند که استفاده از hash برای نگهداری دادهها در برخی مواقع نه تنها کمکی به افزایش پرفورمنس نمیکند، بلکه پرفورمنس برنامه را کاهش میدهد. نیما که حرف محمدرضا را قبول ندارد، از او درخواست کدی کرده است تا میزان hash collision ها را ببیند. محمدرضا نیز این کار را به شما محول کرده است.
در این سؤال، یک HashSet
یا HashMap
به شما داده میشود. شما باید تعداد یکتای hash code های مقادیر موجود در HashSet
یا کلیدهای موجود در HashMap
را محاسبه کرده و برگردانید.
پروژهی اولیه را از این لینک دانلود کنید. ساختار فایلهای پروژه بهصورت زیر است:
HashCollisionChecker
🔗این کلاس شامل دو متد زیر است که باید آنها را پیادهسازی کنید:
HashSet
🔗این متد را طوری پیادهسازی کنید که با دریافت یک HashSet
، تعداد یکتای hash code های مقادیر موجود در آن را برگرداند.
HashSet
🔗این متد را طوری پیادهسازی کنید که با دریافت یک HashMap
، تعداد یکتای hash code های کلیدهای موجود در آن را برگرداند.
با اجرای متد main
موجود در کلاس HashCollisionChecker
:
خروجی باید بهصورت زیر باشد:
hashCode
استفاده کنید.HashCollisionCheckerSampleTest
موجود هستند. با افزودن JUnit به classpath پروژه، میتوانید آنها را اجرا کنید.پس از پیادهسازی متدها، فایل HashCollisionChecker.java
را آپلود کنید.
سلیب که در خلوت خود در حال تفکری عمیق درباره اردرهای مختلف بود، به این فکر فرو رفت که متدهایی که پیادهسازی کرده چقدر طول میکشند و چقدر بهینه کد میزند. برای همین سراغ پیادهسازی متدی برای سنجش زمان موردنیاز برای اجرای هر متد خود رفت. در ادامه به توضیح این متد میپردازیم.
پروژهی اولیه را از این لینک دانلود کنید.
ساختار فایلهای پروژه بهصورت زیر است:
شما باید متد measureExecutionTime
موجود در کلاس ExecutionTime
را مطابق با خواست سؤال پیادهسازی کنید. امضای این متد بهصورت زیر است:
این متد باید Runnable
ای که به آن ورودی داده میشود را اجرا کند و زمان مورد نیاز برای اجرای آن را با واحد ثانیه در متغیری از جنس BigDecimal
دقیقاً با ۵ رقم پس از اعشار برگرداند. برای کاهش ارقام اعشار باید عدد را از پنجمین رقم در ممیز گرد کنید (برای این کار، میتوانید از RoundingMode.HALF_UP
استفاده کنید).
run
در شیء Runnable
متد را اجرا میکند.پس از پیادهسازی موارد خواستهشده، فایل ExecutionTimeCalculator.java
را آپلود کنید.
طبق آماری که گوگل در سال ۲۰۱۶ منتشر کرد، ٪۵۳ از بازدیدکنندگان، یک وبسایت را در صورتی که لود آن بیش از ۳ ثانیه طول بکشد رها میکنند! این آمار، ابوالفضل را به این فکر فرو برده که سرعت لود یک وبسایت به چه اندازه روی حس رضایت کاربران آن وبسایت تأثیر دارد. او که حالا هشتگ #SpeedMatters
را در شبکههای اجتماعی ترند کرده، به این فکر افتاده که سرعت لود برنامهاش را با استفاده از cache بالا ببرد. او برای این کار نیاز به یک دولوپر دیگر دارد و از شما کمک خواسته است.
پروژهی اولیه را از این لینک دانلود کنید. ساختار فایلهای پروژه بهصورت زیر است:
شما باید کلاس Cache
را طوری کامل کنید تا خواستههایی را که در ادامه مطرح میشود را برآورده کند.
ساختار اولیهی این کلاس بهصورت زیر است:
همانطور که مشخص است، cache ما قرار است آیتمهای مختلفی را توسط کلاس CacheItem
درون خود نگه دارد. این آیتمها فعلاً شامل دو کلاس Photo
و Comment
میشوند. همچنین این آیتمها زمان مجازی دارند که توسط پراپرتی TTL
(واحد روز) مشخص میشود. در اولین گام باید کلاس CacheItem
را کامل کنید.
CacheData
🔗این اینترفیس، بیانگر دادههای موجود در cache است. متد زیر در این اینترفیس تعریف شده است:
کلاسهای Comment
و Photo
این اینترفیس را پیادهسازی میکنند.
CacheItem
🔗این کلاس بهصورت generic بوده و مشخصکنندهی آیتمهایی است که درون cache نگه داشته میشوند. این کلاس باید شامل دو پراپرتی data
از نوع T
(بهصورت generic) و createdAt
از نوع LocalDateTime
باشد.
از پراپرتی createdAt
برای بررسی مجاز بودن یک آیتم cache استفاده میشود. زمان مجاز زنده بودن یک آیتم درون cache طبق مقدار پراپرتی TTL
در کلاس Cache
برابر با ۲ روز است.
Cache
🔗همانطور که گفته شد، مهمترین بخش برنامه، این کلاس است. شما باید متدهایی را که در ادامه ذکر میشود را در این کلاس پیادهسازی کنید:
add
: این متد که ورودی آن CacheItem
است، باید بتواند یک آیتم را به cache اضافه کند. دقت کنید که آیتمی با دیتای تکراری نباید در cache وجود داشته باشد. در اینصورت، آیتم قبلی باید از لیست آیتمها حذف شده و آیتم جدید درج شود.remove
: این متد که ورودی آن CacheItem
است، باید بتواند یک آیتم را از cache حذف کند.دو متد بالا را باید بتوان به روش method chaining صدا زد. مثال:
clear
: این متد تمام آیتمهای درون cache را حذف میکند.getAll
: این متد تمام آیتمهای مجاز درون cache را در قالب لیستی از CacheItem
ها برمیگرداند.findByID
: این متد یک پارامتر ورودی از نوع long
دارد و باید لیستی از CacheItem
های مجاز را در صورتی که پراپرتی ID
آیتم درون cache با پارامتر ورودی برابر بود برگرداند.filter
: این متد دو امضا بهصورت زیر دارد:String
است. دومین پارامتر، یک عبارت باقاعده (Regex) بهصورت String
است. در این حالت، تضمین میشود که پراپرتیای با نام ذکرشده در همهی دادههای موجود در cache تعریف شده است.کاری که این متد انجام میدهد آن است که باید در پراپرتی گفتهشده، عبارت باقاعده را جستوجو کند و لیستی از CacheItem
های مجاز را برگرداند. به عنوان مثال فرض کنید دو آیتم زیر درون cache وجود دارند:
حال متد filter
را بهصورت زیر صدا میزنیم و میخواهیم عکسهای با فرمت png
را فیلتر کنیم:
خروجی باید بهصورت زیر باشد:
export
: از این متد نیز قرار است برای بهدست آوردن آماری در رابطه با آیتمهای درون cache استفاده کنیم. خروجی این متد لیستی از ExportCacheDTO
ها است. مثالی از خروجی این متد:این خروجی به این معنی است که ۲ آیتم از نوع Photo
و ۳ آیتم از نوع Comment
درون cache وجود دارد.
services/Cache.java
و services/CacheItem.java
هستید.CacheSampleTest
موجود هستند. میتوانید آنها را پس از افزودن JUnit به classpath در سیستم خود اجرا کنید.پس از پیادهسازی موارد خواستهشده، پوشهی services
را زیپ کرده و آپلود کنید (خود پوشه نیز در فایل زیپ موجود باشد).
علی در شبکهای اجتماعی، کانالهایی برای فوتبالیها دارد. او میخواهد برنامهی زمانبندی بازیهای فوتبال پیش رو را در کانالهایش بهصورت خودکار ارسال کند. همچنین، میخواهد پیش از شروع هر بازی، یک پیام یادآوری بهصورت خودکار بفرستد. برای این کار، او باید اطلاعات بازیها را داشته باشد. از شما میخواهیم برنامهای بنویسید که این اطلاعات را از صفحات وب جمعآوری کند.
پروژهی اولیه را از این لینک دانلود کنید. ساختار فایلهای پروژه بهصورت زیر است:
Country
🔗هر نمونه از این کلاس، بیانگر یک کشور است. هر Country
دارای یک name
از نوع String
بوده که بیانگر نام کشور است. این کلاس از قبل بهطور کامل پیادهسازی شده است.
Stadium
🔗هر نمونه از این کلاس، بیانگر یک استادیوم است. هر Stadium
دارای ویژگیهای زیر است:
name
) از نوع String
country
) از نوع Country
capacity
) از نوع int
این کلاس از قبل بهطور کامل پیادهسازی شده است.
Team
🔗هر نمونه از این کلاس، بیانگر یک تیم است. هر Team
دارای یک name
از نوع String
بوده که بیانگر نام کشور است. این کلاس از قبل بهطور کامل پیادهسازی شده است.
Match
🔗هر نمونه از این کلاس، بیانگر یک مسابقه است. هر Match
دارای ویژگیهای زیر است:
time
) از نوع Date
group
) از نوع String
team1
) از نوع Team
team2
) از نوع Team
stadium
) از نوع Stadium
این کلاس از قبل بهطور کامل پیادهسازی شده است.
WorldCupCrawler
🔗این کلاس، وظیفهی استخراج اطلاعات بازیها از صفحات وب را برعهده دارد. عملیات استخراج دادهها باید تا حد امکان با استفاده از چند thread انجام شود تا سرعت بیشتری داشته باشد. این کلاس در کانستراکتور خود یک آبجمت از نوع URL
دریافت میکند که بیانگر آدرس صفحهی لیست بازیها است. نمونهای از صفحهی لیست بازیها در فایل www/index.html
موجود است.
getStadium
این کلاس را طوری پیادهسازی کنید که با دریافت یک URL
، اطلاعات یک استادیوم را از URL
دادهشده استخراج کرده و در قالب یک آبجکت از نوع Stadium
برگرداند. نمونهای از نحوهی فراخوانی این متد:getMatches
را طوری پیادهسازی کنید که با ارسال درخواست به آدرس واردشده در کانستراکتور، اطلاعات بازیها را در قالب یک List
از Match
ها برگرداند.نکته: تستهای نمونهی سؤال در کلاس WorldCupCrawlerSampleTest
موجود هستند. با افزودن JUnit به classpath پروژه، میتوانید آنها را اجرا کنید. کلاسهای Server
و HtttpHandler
نیز جزو کلاسهای کمکی برای تست هستند.
پس از پیادهسازی موارد خواستهشده، فایل WorldCupCrawler.java
را آپلود کنید.
سلیب که از امنیت کوئرا به ستوه آمده بود، با نیما (اسطورهی امنیت در سطح بینالمللی) در اینباره صحبتی را شروع کرد. نیما به این نتیجه رسید که کوئرا نیاز به یک اقدام امنیتی در ورود به حساب کاربری دارد. پیشنهاد او تأیید از طریق SMS بود و تأکید اکیدی بر زمان انقضای آنها داشت. به نظر او هر کد تأیید باید فقط برای ۱۰ ثانیه معتبر میبودند و پس از گذشت بیش از ۱۰ ثانیه، کد دیگر مورد قبول نباشد. سلیب از آنسو تاکید بر ماندگاری دیتاها داشت. به نظر او نیاز بود تا تمامی اطلاعات را به فرمت زیر در یک فایل CSV نگهداری کند:
در ستون اول شماره مورد نظر، ستون دوم کد ساخته شده برای شماره و در ستون سوم اعتبار کد را نمایش میدهد، در ادامه به بیان جزئیات بیشتر سؤال میپردازیم.
پروژهی اولیه را از این لینک دانلود کنید.
ساختار فایلهای پروژه بهصورت زیر است:
شما باید متدهای generateCode
، sendAuthenticationSMS
، loadData
، verifyCode
موجود در کلاس SMSAuthentication
را مطابق با خواستههای سؤال پیادهسازی کنید. نمای کلی فایل مورد نظر به شکل زیر است:
generateCode
🔗این متد باید یک رشته تصادفی به طول ۵ بسازد و مقدار آن را برگرداند. در این رشته میتوانید از فقط متشکل از ارقام انگلیسی استفاده کنید. نمونهی اجرای متد در زیر آمده است:
sendAuthenticationSMS
🔗این متد یک رشته به عنوان شماره و رشتهای دیگر به عنوان آدرس فایلی که باید اطلاعات را در آن ذخیره کند، به عنوان ورودی دریافت میکند. خروجی این متد باید رشتهای به فرمت JSON
باشد. در خروجی JSON
مورد نظر باید کلید و مقدارهای زیر را داشته باشد:
phone
برابر با مقدار شماره مورد نظر خواهد بود.code
برابر با کد ساخته شده برای شماره مورد نظر خواهد بود.exp
برابر با زمانی که کد مورد نظر منقضی میشود است، زمان در این سؤال به فرمت "yyyy/MM/dd-HH:mm:ss"
استفاده میشود.این متد باید این محتوا را درون فایل CSV موجود در آدرس path
ذخیره کند. خروجی و رفتار خواسته شده در بخش مثال با جزئیات بیشتری نمایش داده شده است.
محتوای چند خط آخر فایل test.csv
پس از اجرای بالا برابر با زیر خواهد بود:
loadData
🔗این متد یک رشته به عنوان آدرس فایلی که باید اطلاعات آن را بخواند، به عنوان ورودی دریافت میکند. خروجی این متد لیستی از آرایهای از String
ها خواهد بود که برابر با مقادیر موجود در فایل CSV ورودی متد است.
برای مثال فرض کنید محتوای فایل CSV بهصورت زیر باشد:
اگر متد را بهصورت زیر فراخوانی کنیم
و بخواهیم خروجی متد را بهصورت زیر چاپ کنیم:
خروجی بهصورت زیر خواهد بود
دقت کنید که خط اول (یا همان Phone,Code,Expiration
) در خروجی متد وجود ندارد.
verifyCode
🔗این متد یک رشته به عنوان کد، یک رشته به عنوان شماره و رشتهای دیگر به عنوان آدرس فایلی که باید اطلاعات را از آن بخواند، به عنوان ورودی دریافت میکند. خروجی این متد یک boolean
است که در صورتی که کد با شماره مورد نظر تطابق داشت و کد منقضی نشده بود، باید مقدار true
برگرداند و در غیر این صورت مقدار false
برگرداند.
pom.xml
نیستید.JSON
، تنها مجاز به استفاده از کتابخانه opencsv
هستید.jackson-databind
هستید.pom.xml
، تنها مجاز به استفاده از کتابخانههای استاندارد جاوا هستید.sendAuthenticationSMS
) قرار دهید.پس از پیادهسازی موارد خواستهشده، فایل تمامی پروژه را زیپ کنید و آن را آپلود کنید. فایل زیپ شما باید بهصورتی باشد که پس از خروج از حالت فشرده، پوشهی src
مشاهده شود.
اخیراً وبسایت شخصی نیما مورد حملات مشکوک قرار گرفته است. او در حال بررسی لاگهای وبسرور سایتش است تا دریابد این حملات از کدام سمت بودهاند، اما برای این کار از یک ویرایشگر متنی ساده استفاده میکند. او میخواهد بتواند روی لاگها فیلتر اعمال کند تا جستوجوی هدفمندی داشته باشد. از شما میخواهیم چنین برنامهای را برای او پیادهسازی کنید.
پروژهی اولیه را از این لینک دانلود کنید. ساختار فایلهای پروژه بهصورت زیر است:
exceptions
🔗این بسته شامل استثناهای موردنیاز برنامه است. همهی کلاسهای موجود در این بسته از کلاس RuntimeException
ارثبری میکنند.
Log
🔗هر نمونه از این کلاس بیانگر لاگ یک درخواست است. هر لاگ شامل یک یا چند ویژگی است. این کلاس از قبل بهطور کامل پیادهسازی شده و شامل متدهای زیر است:
setProperty(String name, String value)
: این متد با دریافت نام و مقدار یک ویژگی، آن ویژگی را به ویژگیهای لاگ اضافه میکند.getProperty(String name)
: این متد با دریافت نام یک ویژگی، مقدار آن ویژگی را برمیگرداند. در صورتی که ویژگیای با نام واردشده موجود نباشد، یک استثنا از نوع PropertyNotFoundException
پرتاب میشود.LogPropertyTransformerRepository
🔗بعضی از ویژگیهای لاگها (مانند کد وضعیت پاسخ و زمان ارسال درخواست) ماهیت عددی دارند. این کلاس، مجموعهای از Function<String, Long>
را در خود نگهداری میکند تا با استفاده از آنها، بتوان مقدار عددی معادل بعضی از ویژگیهای لاگها را دریافت کرد. این کلاس از قبل بهطور کامل پیادهسازی شده و شامل متدهای زیر است:
addTransformer(String propertyName, Function<String, Long> transformer)
: این متد با دریافت نام یک ویژگی و یک تابع برای تبدیل مقدار رشتهای ویژگی به مقدار عددی، آن تابع را در Map
موجود در کلاس ذخیره میکند.getTransformer(String propertyName)
: این متد با دریافت نام یک ویژگی، تابع مبدل مقدار آن ویژگی به مقدار عددی را برمیگرداند. در صورتی که تابعی برای ویژگی موردنظر تعریف نشده باشد، یک استثنا از نوع TransformerNotFoundException
پرتاب میشود.Condition
🔗هر نمونه از این کلاس، بیانگر یک شرط (ساده یا مرکب) برای فیلتر کردن لاگها است. پراپرتیهای موردنیاز خود را در این کلاس تعریف کرده و متدهای زیر را در آن پیادهسازی کنید:
equal(String propertyName, String value)
را طوری پیادهسازی کنید که با دریافت نام و مقدار یک ویژگی، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط معادل بودن ویژگی با مقدار موردنظر در آن موجود باشد.notEqual(String propertyName, String value)
را طوری پیادهسازی کنید که با دریافت نام و مقدار یک ویژگی، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط معادل نبودن ویژگی با مقدار موردنظر در آن موجود باشد.in(String propertyName, String... values)
را طوری پیادهسازی کنید که با دریافت نام یک ویژگی و تعدادی مقدار، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط معادل بودن ویژگی با حداقل یکی از مقادیر واردشده در آن موجود باشد.in(String propertyName, String... values)
را طوری پیادهسازی کنید که با دریافت نام یک ویژگی و تعدادی مقدار، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط معادل نبودن ویژگی با هیچ یک از مقادیر واردشده در آن موجود باشد.lessThan(String propertyName, Long value)
را طوری پیادهسازی کنید که با دریافت نام یک ویژگی و یک عدد، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط کوچکتر بودن مقدار عددی ویژگی از عدد واردشده در آن موجود باشد. برای پیادهسازی این متد، از کلاس LogPropertyTransformerRepository
استفاده کنید.lessOrEqual(String propertyName, Long value)
را طوری پیادهسازی کنید که با دریافت نام یک ویژگی و یک عدد، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط کوچکتر یا مساوی بودن مقدار عددی ویژگی از عدد واردشده در آن موجود باشد. برای پیادهسازی این متد، از کلاس LogPropertyTransformerRepository
استفاده کنید.greaterThan(String propertyName, Long value)
را طوری پیادهسازی کنید که با دریافت نام یک ویژگی و یک عدد، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط بزرگتر بودن مقدار عددی ویژگی از عدد واردشده در آن موجود باشد. برای پیادهسازی این متد، از کلاس LogPropertyTransformerRepository
استفاده کنید.greaterOrEqual(String propertyName, Long value)
را طوری پیادهسازی کنید که با دریافت نام یک ویژگی و یک عدد، یک نمونه از کلاس Condition
برگرداند که اطلاعات مربوط به شرط بزرگتر یا مساوی بودن مقدار عددی ویژگی از عدد واردشده در آن موجود باشد. برای پیادهسازی این متد، از کلاس LogPropertyTransformerRepository
استفاده کنید.and(Condition condition)
را طوری پیادهسازی کنید که با دریافت یک شرط، یک نمونه از کلاس Condition
برگرداند که شرط آن برابر با AND منطقی شرط فعلی و شرط واردشده باشد.or(Condition condition)
را طوری پیادهسازی کنید که با دریافت یک شرط، یک نمونه از کلاس Condition
برگرداند که شرط آن برابر با OR منطقی شرط فعلی و شرط واردشده باشد.not(Condition condition)
را طوری پیادهسازی کنید که با دریافت یک شرط، یک نمونه از کلاس Condition
برگرداند که شرط آن برابر با NOT منطقی شرط فعلی و شرط واردشده باشد.test(Log log)
را طوری پیادهسازی کنید که با دریافت یک لاگ، در صورتی که لاگ در شرایط فعلی صدق کند، مقدار true
و در غیر اینصورت، مقدار false
را برگرداند.نکته: متدهای and
، or
و not
را باید بهگونهای پیادهسازی کنید که نمونههای جدیدی از کلاس Condition
ایجاد شوند. در واقع، نمونههای کلاس Condition
باید immutable باشند.
LogList
🔗این کلاس، یک List
از لاگها را در خود نگهداری میکند.
all
این کلاس را طوری پیادهسازی کنید که یک LogList
شامل یک List
جدید که لاگهای موجود در آبجکت فعلی در آن قرار گرفتهاند ایجاد کرده و برگرداند.where
این کلاس را طوری پیادهسازی کنید که با دریافت یک Condition
، یک LogList
شامل یک List
جدید که لاگهای موجود در آبجکت فعلی در آن قرار گرفتهاند و در شرط واردشده صدق میکنند ایجاد کرده و برگرداند. ترتیب لاگهای موجود در لیست را نباید تغییر دهید.LogParser
🔗وظیفهی این کلاس، پارس کردن رشتهی لاگها است. لاگها یک schema مشخص دارند که در قالب یک رشته به کانستراکتور این کلاس داده میشود. schema شامل تعدادی متغیر نیز هست که با $
آغاز میشوند. مثالی از یک schema:
در اینصورت، لاگهای پارسشده باید شامل ویژگیهای remote_addr
، remote_user
و... باشند.
نمونهای از یک لاگ که طبق فرمت schema بالا است:
parseLog(String line)
این کلاس را طوری پیادهسازی کنید که با دریافت یک رشتهی یکخطی، یک Log
متناظر با لاگ واردشده برگرداند. در صورتی که لاگ واردشده با schema دادهشده مطابقت نداشت، یک استثنا از نوع LineDoesNotMatchException
پرتاب کنید. ترتیب ویژگیهای Log
خروجی باید مطابق ترتیب متغیرهای موجود در schema باشد.parseLogs(String logs)
را طوری پیادهسازی کنید که با دریافت یک رشتهی یک یا چند خطی، یک LogList
متناظر با لاگهای واردشده برگرداند. برای پیادهسازی این متد، از متد parseLog(String line)
استفاده کنید.parseLogs(File file)
را طوری پیادهسازی کنید که با دریافت یک فایل، یک LogList
متناظر با لاگهای موجود در آن برگرداند. برای پیادهسازی این متد، از متد parseLogs(String logs)
استفاده کنید.با اجرای متد main
موجود در کلاس LogParser
:
خروجی باید بهصورت زیر باشد:
نکته: تستهای نمونهی سؤال در کلاس LogParserSampleTest
موجود هستند. با افزودن JUnit به classpath پروژه، میتوانید آنها را اجرا کنید.
پس از پیادهسازی موارد خواستهشده، یک فایل زیپ آپلود کنید که وقتی آن را باز میکنیم، با فایلهای زیر مواجه شویم: