NEW: Start my new Ultimate Portfolio App course with a free Hacking with Swift+ trial! >>

Refactoring with a function having a struct property as argument

Forums > SwiftUI

Hello everybody, in the following code, how could you write a makeList() function to replace countryList() and cityList(), given that country and city are properties of a struct Customer


let customers: [Customer] = Bundle.main.decode("customers.json")

func countryList() -> [String] { var array = [String]() for customer in customers { if !array.contains(customer.country) { array.append(customer.country) } } return array }

func cityList() -> [String] { var array = [String]() for customer in customers { if !array.contains(customer.city) { array.append(customer.city) } } return array }


   

Hi @peacockadoodle If you put code in </> then it will be easy to read eg

let customers: [Customer] = Bundle.main.decode("customers.json")

func countryList() -> [String] {
  var array = [String]()

  for customer in customers {
    if !array.contains(customer.city) {
      array.append(customer.city)
    }
  }
  return array
}

func cityList() -> [String] {
  var array = [String]()

  for customer in customers {
    if !array.contains(customer.country) {
      array.append(customer.country)
    }
  }
  return array
}

Not sure what you what to do with the properties.

   

Hi and thank you @NigelGee.

I would like to create a general function that could accept the name of a Customer property as an argument, but if I do so, I can't use it in the dot notation.

func makeList( customerProperty: String) -> [String] {
  var array = [String]()

  for customer in customers {
    if !array.contains(customer.customerProperty) {
      array.append(customer.customerProperty)
    }
  }
  return array
}

   

Hey, it is not very clear what you are trying to do here, but here's my best guess (correct me if wrong):

You would like to have a single function which, when called, returns an array containing a collection of one of the properties of the Customer struct. in other words, the same function will sometimes return an array containing the city of each Customer instance, other times the country property.

If that is what you want, then you should be thinking about the function parameter(s) required to make it happen. The question becomes: How do I let the function know which properties to check in the for loop.

Which you could achieve by using an enum that lists the properties, and then inside your function, you switch over that enum. Each case will contain the for loop relevant to that property.

Therefore, your function will need to take that enum as it's parameter.

Try it out, and if you still need help with it, do let us know. 😉

   

hi Mr. Peacock,

rather than inventing many different functions, or trying to unify them with some syntax using a parameter (keypaths come to mind), i would suggest using something more direct at the call site.

example: to get a list of the countries represented among your customers, how about pulling out the country values with map, and turning that into a Set

let countries: Set<String> = Set(customers.map({ $0.country }))

if you need the result specifically as an Array, rather than as a Set, you can use

let countries: [String] = Array(Set(customers.map({ $0.country })))

or if you want a sorted array, then

let countries: [String] = Set(customers.map({ $0.country })).sorted()

hope that helps,

DMG

   

Hacking with Swift is sponsored by Stream

SPONSORED Check out Stream's cross-platform open source chat SDK on GitHub! Write once and deploy your app with fully featured chat UI on iOS and macOS.

Go to GitHub

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.