Purpose of project: allow an employee to calculate/project future income based on several future promotions. With promotions come pay raises.
Current challenge to overcome: Create an array in which each element represents the average hourly payrate of that year.
The below employee example worked in the following departments:
First year: Sanitation (other)
Second year: Hospitality (other)
Third & fourth years: Sales
Fifth year: Management
Sixth through eighth years: Senior Management
These are their repsective payscales:
sales: rates = [20,22,24,26,28,30,32,34,36,38,40]
management: rates = [30,32,34,36,38,40,42,44,46,48,50]
seniorManagement: rates = [40,42,44,46,48,50,52,54,56,58,60]
other (sanitation & hospitality): rates = [10,12,14,16,18,20,22,24,26,28,30]
The array of average hourly payrates for each year should be:
[10, 12, 24, 26, 38, 50, 52, 54]
My current best effort is not successful at producing the above array. Instead I get:
[12, 12, 24, 24, 36, 48, 48, 24]
The last element is 24
because the employee did work a full 12 months before retiring. I'm not concerned about that particular element. I'm energized about figuring out why the other elements are incorrect.
The below code can be pasted into Playground:
extension Array {
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[$0 ..< Swift.min($0 + size, count)])
}
}
}
enum Department: RawRepresentable {
case sales
case management
case seniorManagement
case other(String)
init?(rawValue: String) {
switch rawValue {
case "Sales": self = .sales
case "Management": self = .management
case "Senior Management": self = .seniorManagement
case let dept: self = .other(dept)
}
}
var rawValue: String {
switch self {
case .sales: return "Sales"
case .management: return "Management"
case .seniorManagement: return "Senior Management"
case .other(let dept): return dept
}
}
func payRate(forYearsWorked numberOfYears: Int) -> Double {
let rates: [Double]
switch self {
case .sales: rates = [20,22,24,26,28,30,32,34,36,38,40]
case .management: rates = [30,32,34,36,38,40,42,44,46,48,50]
case .seniorManagement: rates = [40,42,44,46,48,50,52,54,56,58,60]
default: rates = [10,12,14,16,18,20,22,24,26,28,30]
}
return rates[min(numberOfYears, rates.count) - 1]
}
}
struct Employee: Identifiable, Equatable, Hashable {
static func ==(lhs: Employee, rhs: Employee) -> Bool {
return lhs.id == rhs.id
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
var id = UUID()
let name: String
var birthdate: Date
var hiredate: Date
var retirementAge: Int
var department: Department
var monthlyHoursWorked: Double
var planningToPromote1: Bool
var planningToPromote2: Bool
var planningToPromote3: Bool
var planningToPromote4: Bool
var promotion1Date: Date
var promotion2Date: Date
var promotion3Date: Date
var promotion4Date: Date
var secondDepartment: Department
var thirdDepartment: Department
var fourthDepartment: Department
var fifthDepartment: Department
var regularPayRateIncreases: Bool
var regularPayRateIncreasePercentage: Int
var regularPayRateIncreaseYearInterval: Int
private(set) var employmentHistory: [Department]
init(_ name: String,
birthdate: Date,
hiredate: Date,
retirementAge: Int,
department: Department = .other("Employee"),
monthlyHoursWorked: Double,
planningToPromote1: Bool,
planningToPromote2: Bool,
planningToPromote3: Bool,
planningToPromote4: Bool,
promotion1Date: Date,
promotion2Date: Date,
promotion3Date: Date,
promotion4Date: Date,
secondDepartment: Department = .other("Employee"),
thirdDepartment: Department = .other("Employee"),
fourthDepartment: Department = .other("Employee"),
fifthDepartment: Department = .other("Employee"),
regularPayRateIncreases: Bool,
regularPayRateIncreasePercentage: Int,
regularPayRateIncreaseYearInterval: Int)
{
self.name = name
self.birthdate = birthdate
self.hiredate = hiredate
self.retirementAge = retirementAge
self.department = department
self.monthlyHoursWorked = monthlyHoursWorked
self.planningToPromote1 = planningToPromote1
self.planningToPromote2 = planningToPromote2
self.planningToPromote3 = planningToPromote3
self.planningToPromote4 = planningToPromote4
self.promotion1Date = promotion1Date
self.promotion2Date = promotion2Date
self.promotion3Date = promotion3Date
self.promotion4Date = promotion4Date
self.secondDepartment = secondDepartment
self.thirdDepartment = thirdDepartment
self.fourthDepartment = fourthDepartment
self.fifthDepartment = fifthDepartment
self.regularPayRateIncreases = regularPayRateIncreases
self.regularPayRateIncreasePercentage = regularPayRateIncreasePercentage
self.regularPayRateIncreaseYearInterval = regularPayRateIncreaseYearInterval
self.employmentHistory = []
}
}
extension Employee {
mutating func promote(to newDepartment: Department) {
department = newDepartment
}
mutating func work(months: Int) {
employmentHistory
.append(contentsOf: Array.init(repeating: department,
count: months))
}
mutating func work(years: Int) {
work(months: years * 12)
}
mutating func work(years: Int, months: Int) {
work(months: years * 12 + months)
}
func employmentHistoryPayRates() -> [Double] {
let years = employmentHistory.chunked(into: 12)
var historyOfPayRates: [Double] = []
for (index, months) in years.enumerated() {
let employmentHistoryPayRates: Double = months.reduce(0) {result, dept in
let payRate = dept.payRate(forYearsWorked: index + 1
)/12
return Double(String(format: "%.0f", result + payRate)) ?? result + payRate
}
historyOfPayRates.append(employmentHistoryPayRates)
}
return historyOfPayRates
}
}
extension Employee {
func yearlyDepartments() -> [String] {
let years = employmentHistory.chunked(into: 12)
let departments: [String] = years.map { months in
var seenDepts: Set<String> = []
return months.reduce(into: [String]()) { acc, dept in
if seenDepts.insert(dept.rawValue).inserted {
acc.append(dept.rawValue)
}
}.joined(separator: ",")
}
return departments
}
func yearlyDepartmentsRates() -> [(String, Double)] {
let yearlyDepartments = yearlyDepartments()
let yearlyRates = employmentHistoryPayRates()
let yearlyDepartmentsRates: [(departments: String, rates: Double)] =
Array(zip(yearlyDepartments, yearlyRates))
return yearlyDepartmentsRates
}
}
var birthdate = DateComponents(calendar: .current, year: 1965, month: 7, day: 20).date!
var hiredate = DateComponents(calendar: .current, year: 2022, month: 12, day: 28).date!
var promotion1date = DateComponents(calendar: .current, year: 2023, month: 12, day: 28).date!
var firstDeptMonths: Int { Calendar.current.dateComponents([.month], from: hiredate, to: promotion1date).month! }
var promotion2date = DateComponents(calendar: .current, year: 2024, month: 12, day: 28).date!
var secondDeptMonths: Int { Calendar.current.dateComponents([.month], from: promotion1date, to: promotion2date).month! }
var promotion3date = DateComponents(calendar: .current, year: 2026, month: 12, day: 28).date!
var thirdDeptMonths: Int { Calendar.current.dateComponents([.month], from: promotion2date, to: promotion3date).month! }
var promotion4date = DateComponents(calendar: .current, year: 2027, month: 12, day: 28).date!
var fourthDeptMonths: Int { Calendar.current.dateComponents([.month], from: promotion3date, to: promotion4date).month! }
var retireAge = 65
let retireDate = Calendar.current.date(byAdding: .year, value: retireAge, to: birthdate)!
var fifthDeptMonths: Int { Calendar.current.dateComponents([.month], from: promotion4date, to: retireDate).month! }
extension Date {
var age: Int { Calendar.current.dateComponents([.year], from: self, to: Date()).year! }
var yearGroup: Int { Calendar.current.dateComponents([.year], from: self, to: Date()).year! + 1 }
var totalYearsRemaining: Int { Calendar.current.dateComponents([.year], from: self, to: retireDate).year! }
var totalMonthsRemaining: Int { Calendar.current.dateComponents([.month], from: self, to: retireDate).month! }
}
//age of employee
let age = birthdate.age
//number of years employee has worked for the company
let yearGroup = hiredate.yearGroup
func printYearlyDepartments(_ yearlyDepts: [(String)]) {
for (year, depts) in yearlyDepts.enumerated() {
print("Years since hired: \(year + yearGroup + 1)")
print("Department(s) for Year \(year + yearGroup + 1): \(depts)")
print("Age: \(year + age)")
print("")
}
}
func printEmploymentHistoryRates(_ yearlyDeptsAndRates: [(departments: String, rates: Double)]) {
for (year, deptsAndRates) in yearlyDeptsAndRates.enumerated() {
print("Department(s) for Year \(year + yearGroup + 1): \(deptsAndRates.departments)")
print("Payrate for Year \(year + yearGroup + 1): $\(deptsAndRates.rates)")
print("")
}
}
var charlotte = Employee("Charlotte Grote",
birthdate: DateComponents(calendar: .current, year: 1965, month: 7, day: 20).date!,
hiredate: DateComponents(calendar: .current, year: 2021, month: 12, day: 28).date!,
retirementAge: 65,
department: .other("Sanitation"),
monthlyHoursWorked: 160,
planningToPromote1: true,
planningToPromote2: true,
planningToPromote3: true,
planningToPromote4: true,
promotion1Date: DateComponents(calendar: .current, year: 2023, month: 12, day: 28).date!,
promotion2Date: DateComponents(calendar: .current, year: 2025, month: 6, day: 28).date!,
promotion3Date: DateComponents(calendar: .current, year: 2026, month: 12, day: 28).date!,
promotion4Date: DateComponents(calendar: .current, year: 2027, month: 12, day: 28).date!,
secondDepartment: .other("Hospitality"),
thirdDepartment: .other("Sales"),
fourthDepartment: .other("Management"),
fifthDepartment: .other("Senior Management"),
regularPayRateIncreases: true,
regularPayRateIncreasePercentage: 4,
regularPayRateIncreaseYearInterval: 4)
charlotte.work(months: firstDeptMonths)
charlotte.promote(to: .other("Hospitality"))
charlotte.work(months: secondDeptMonths)
charlotte.promote(to: .sales)
charlotte.work(months: thirdDeptMonths)
charlotte.promote(to: .management)
charlotte.work(months: fourthDeptMonths)
charlotte.promote(to: .seniorManagement)
charlotte.work(months: fifthDeptMonths)
charlotte.yearlyDepartmentsRates()
charlotte.employmentHistoryPayRates()