مسیرها
/
Swift
Swift
/
تمرین‌ها
/
میکسولوژیست خبره
میکسولوژیست خبره

میکسولوژیست خبره

تمرین یادگیری

مقدمه

Switch

یک دستور switch به شما امکان می‌دهد یک مقدار را با چندین مقدار منطبق ممکن مقایسه کنید. این دستور به شما امکان می‌دهد کدی موجزتر از استفاده از چندین دستور else-if بنویسید. یک دستور switch با کلیدواژه‌ی switch آغاز می‌شود و پس از آن مقداری می‌آید که باید مقایسه شود. سپس می‌توانید حالت‌ها را با کلیدواژه‌ی case تعریف کنید و پس از آن مقداری می‌آید که باید با آن مقایسه شود. کلیدواژه‌ی default برای تعریف حالت پیش‌فرض به کار می‌رود، یعنی زمانی که هیچ‌یک از حالت‌ها مطابقت نداشته باشند. مانند دستورهای else-if، دستورهای switch تنها بلوک کدی را اجرا می‌کنند که با نخستین حالت منطبق مرتبط است.

switch value {
case 1:
    print("One")
case 2:
    print("Two")
default:
    print("Other")
}

مثال زیر را در نظر بگیرید:

if str == "apple" {
    print("Let's bake an apple crumble")
} else if str == "lemon" {
    print("Let's bake a lemon meringue pie!")
} else if str == "peach" {
    print("Let's bake a peach pie!")
} else {
    print("Let's buy ice cream.")
}

در عوض می‌توان این را چنین نوشت:

switch str {
case "apple":
    print("Let's bake an apple crumble")
case "lemon":
    print("Let's bake a lemon meringue pie!")
case "peach":
    print("Let's bake a peach pie!")
default:
    print("Let's buy ice cream.")
}

حلقه‌های while

یک حلقه‌ی while یک دستور جریان کنترل است که امکان می‌دهد کد تا زمانی که یک شرط خاص «درست» است اجرا شود. Swift دو نوع حلقه‌ی while ارائه می‌دهد: حلقه‌های while و repeat-while. شرط حلقه‌ی while پیش از اجرای بدنه‌ی حلقه ارزیابی می‌شود؛ اگر شرط «غلط» باشد، بدنه‌ی حلقه به‌کلی اجرا نخواهد شد. حلقه‌های while در Swift ساختار زیر را دارند:

while <#condition#> {
  <#code#>
}

در اینجا حلقه تا زمانی که count بزرگ‌تر از ۰ باشد اجرا می‌شود و در نتیجه اعداد ۲، ۱ و «Liftoff!» را چاپ می‌کند.

var count = 2
while count > 0 {
  print("\(count)…")
  count -= 1
}
print("Liftoff!")

// prints:
// 2…
// 1…
// Liftoff!

یک حلقه‌ی repeat-while شبیه حلقه‌ی while است، اما شرط پس از اجرای بدنه‌ی حلقه ارزیابی می‌شود. این یعنی بدنه‌ی حلقه همیشه دست‌کم یک بار اجرا می‌شود، حتی اگر شرط «غلط» باشد. حلقه‌های repeat-while در Swift ساختار زیر را دارند:

repeat {
  <#code#>
} while <#condition#>

در اینجا حلقه فقط یک بار اجرا می‌شود، چون شرط «غلط» است. چون این یک حلقه‌ی repeat-while است، بدنه‌ی حلقه پیش از ارزیابی شرط یک بار اجرا می‌شود.

var count = 2
repeat {
  print("\(count)…")
} while count < 0
print("Liftoff!")

انتقال کنترل

Swift مجموعه‌ای از دستورها دارد که می‌توان از آن‌ها برای تغییر جریان کنترل عادی حلقه‌ها استفاده کرد. به این‌ها دستورهای انتقال کنترل می‌گویند. شما پیش‌تر return را دیده‌اید؛ این مفهوم موارد دیگری را معرفی می‌کند که شامل continue، break و برچسب‌هاست. در این مفهوم به fallthrough نمی‌پردازیم، اما می‌توانید درباره‌ی آن در کتاب Swift بخوانید.

Continue

گاهی لازم است زودتر به تکرار بعدی حلقه بپرید، بدون آنکه بقیه‌ی دستورهای تکرار کنونی حلقه را کامل کنید. کلیدواژه‌ی continue برای این کار به کار می‌رود. وقتی continue اجرا می‌شود، حلقه به بررسی بعدی می‌پرد تا ببیند آیا تکرار بعدی حلقه قابل اجراست یا نه، یعنی while در حلقه‌های while و repeat-while، یا بررسی این‌که آیا عنصر دیگری در دنباله هست یا نه در حلقه‌های for-in.

count = 1
while count < 6 {
  count += 1
  if count == 4 { continue }
  print(count)
}

// prints:
// 2
// 3
// 5

Break

از break برای خروج زودتر از حلقه استفاده می‌شود. وقتی break اجرا می‌شود، حلقه بی‌درنگ خارج می‌شود و برنامه با نخستین دستور پس از حلقه ادامه می‌یابد.

for fruit in ["banana", "grapes", "apple", "strawberry", "kiwi", "lemon"] {
  if !fruit.count.isMultiple(of: 2) { break }
  print(fruit)
}

// prints:
// banana
// grapes

برچسب‌ها

وقتی حلقه‌ها تودرتو هستند، گاهی ممکن است بخواهید از break یا continue استفاده کنید تا از حلقه‌های بیرونی‌ای که حلقه‌ی به‌کارگیرنده‌ی break یا continue را در خود دارند خارج شوید یا آن‌ها را از نو شروع کنید. در چنین مواردی می‌توان از برچسب‌ها استفاده کرد تا مشخص شود کدام حلقه باید خارج شود یا از نو شروع شود. می‌توان یک حلقه را با قرار دادن یک اسم و سپس یک دونقطه پیش از while، repeat یا for که حلقه را آغاز می‌کند، برچسب‌گذاری کرد.

برای دیدن اثر استفاده از برچسب‌ها به این شکل، حلقه‌ی زیر را در نظر بگیرید.

outerLoop: for fruit in ["banana", "grapes", "apple", "strawberry", "kiwi", "lemon"] {
  print("\n--- \(fruit) ---")
  for letter in fruit {
    guard letter != "n" else { break outerLoop }
    print(letter)
  }
}

// prints:
// --- banana ---
// b
// a

دستورالعمل‌ها

شما یک کوکتل‌ساز حرفه‌ای هستید و نوشیدنی‌های خوشمزه‌ای برای مردم درست می‌کنید تا در شب‌گردی‌هایشان از آن‌ها لذت ببرند. اما به این فکر افتادید که می‌توانید با نوشتن کمی کد کارتان را راحت‌تر کنید تا در شغلتان کمکتان کند.

1. تعیین کنید که آماده کردن یک سفارش چقدر طول می‌کشد

نوشیدنی‌های مختلف زمان آماده‌سازی متفاوتی دارند:

  • "beer"، "soda" و "water" هر کدام ۰٫۵ دقیقه زمان می‌برند.
  • "shot" ۱٫۰ دقیقه، "mixed drink" ۱٫۵ دقیقه،
  • "fancy drink" ۲٫۵ دقیقه،
  • "frozen drink" ۳٫۰ دقیقه.

تابع timeToPrepare(drinks:) را پیاده‌سازی کنید که آرگومان drinks را می‌گیرد؛ این آرگومان آرایه‌ای از رشته‌هاست که نوشیدنی‌های نیازمند آماده‌سازی را نشان می‌دهد. تابع باید کل زمانی را برگرداند که آماده‌سازی همه‌ی نوشیدنی‌های داخل آرایه طول می‌کشد.

timeToPrepare(drinks: ["beer", "frozen drink", "shot"])
// returns 4.5

2. ذخیره‌ی قاچ لایم خود را دوباره پر کنید

یکی از اولین کارهایی که هنگام شروع شیفت باید انجام دهید این است که مطمئن شوید سبد کوچک قاچ‌های لایمتان برای شیفت پیش رو پر است. لایم‌ها اندازه‌های مختلفی دارند و هر اندازه تعداد متفاوتی قاچ می‌دهد؛ از یک لایم "small" ۶ قاچ، از یک لایم "medium" ۸ قاچ و از یک لایم "large" ۱۰ قاچ به دست می‌آید.

تا زمانی که هنوز به قاچ بیشتری نیاز دارید و هنوز لایم بیشتری برای بریدن دارید، اولین لایم را از آرایه بیرون بیاورید و تعداد مناسب قاچ را از مقداری که نیاز دارید کم کنید. این کار را ادامه دهید تا دیگر به قاچ بیشتری نیاز نداشته باشید یا لایم‌هایتان تمام شود.

تابع makeWedges(needed:limes:) را پیاده‌سازی کنید که آرگومان‌های needed و limes را می‌گیرد؛ needed تعداد قاچ‌هایی را نگه می‌دارد که باید ببرید و limes آرایه‌ای از رشته‌هاست که اندازه‌های لایم‌های در دسترس برای بریدن را نشان می‌دهد. تابع باید تعداد لایم‌هایی را که بریده‌اید برگرداند.

makeWedges(needed: 25, limes: ["small", "small", "large", "medium", "small"])
// returns 4

3. شیفت خود را به پایان برسانید

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

تا زمانی که هنوز در شیفتتان زمان باقی است، باید اولین سفارش در آرایه را آماده کنید و سپس همان سفارش را از آرایه حذف کنید. سپس می‌توانید مدت زمانی را که آماده‌سازی آن سفارش طول کشید، بر اساس تابع timeToPrepare(drinks:)، از زمان باقی‌مانده‌ی شیفتتان کم کنید.

تابع finishShift(minutesLeft:remainingOrders:) را پیاده‌سازی کنید که تعداد دقیقه‌های باقی‌مانده از شیفتتان (که تضمین شده بزرگ‌تر از ۰ است) و یک آرایه‌ی غیرخالی از سفارش‌های نوشیدنی را می‌گیرد. تابع باید آرایه‌ی سفارش‌هایی را برگرداند که تا پایان شیفتتان به آن‌ها نرسیده‌اید.

finishShift(minutesLeft: 5, remainingOrders: [["beer", "frozen drink", "shot"], ["fancy drink", "soda"], ["beer", "beer", "water"], ["mixed drink", "frozen drink"]])
// returns [["beer", "beer", "water"], ["mixed drink", "frozen drink"]]

4. سفارش‌های خاص را ردیابی کنید

برای اینکه مطمئن شوید آبجو و نوشابه تازه می‌مانند، باید سفارش‌های آن‌ها را همراه با زمان ثبت هر سفارش پیگیری کنید.

تابع orderTracker(orders: [(drink: String, time: String)]) -> (beer: (first: String, last: String, total: Int)?, soda: (first: String, last: String, total: Int)?) را پیاده‌سازی کنید. این تابع وقتی فهرستی از سفارش‌ها و زمان‌ها را می‌گیرد، یک جفت تاپل اختیاری برمی‌گرداند که زمان اولین و آخرین سفارش آبجو و نوشابه و نیز تعداد کل سفارش‌های هر یک را در بر دارد، و اگر هیچ سفارشی برای آن نوشیدنی‌ها ثبت نشده باشد، nil برمی‌گرداند. لازم نیست نوشیدنی دیگری را ردیابی کنید.

تابع orderTracker(orders:) را پیاده‌سازی کنید که آرایه‌ای از تاپل‌ها را می‌گیرد؛ هر تاپل، نوشیدنی سفارش‌شده و زمان ثبت سفارش را نگه می‌دارد. تابع باید تاپلی برگرداند که شامل زمان اولین و آخرین سفارش آبجو، تعداد کل سفارش‌های آبجو، زمان اولین و آخرین سفارش نوشابه و تعداد کل سفارش‌های نوشابه است. این مقدار باید به صورت تاپلی با این قالب برگردانده شود: (beer: (first: String, last: String, total: Int)?, soda: (first: String, last: String, total: Int)?).

let orders = [
    (drink: "beer", time: "10:01"), (drink: "frozen drink", time: "10:02"),
    (drink: "shot", time: "10:05"), (drink: "fancy drink", time: "10:06"),
    (drink: "soda", time: "10:09"), (drink: "beer", time: "10:15"), (drink: "beer", time: "10:22"),
    (drink: "water", time: "10:26"), (drink: "mixed drink", time: "10:28"),
    (drink: "frozen drink", time: "10:33"),
]

orderTracker(orders: orders)

// returns (beer: (first "10:01", last "10:22", total 3), soda: (first "10:09", last "10:09", total 1))
ویرایش از طریق GitHub این لینک در پنجره یا زبانه‌ی جدیدی باز می‌شود
Swift Exercism

آماده‌اید میکسولوژیست خبره را شروع کنید؟

در Exercism ثبت‌نام کنید تا Swift را همراه با 35 مفهوم116 تمرین و مربی‌گری انسانی واقعی یاد بگیرید و در آن استاد شوید، همه‌ی این‌ها رایگان.