1

I have an array of allMenuItems as below, which I am trying to filter from an array of Id's. How is this achievable in Swift? I have some understanding of higher order functions, but so far I've been unable to filter this successfully. Any pointers on how this could be achieved would be welcome, thanks.

struct MenuItems {
    var id: String
    var name: String

    init() {
        self.id = ""
        self.name = ""
    }
}

var m1 = MenuItems()
m1.id = "1"
m1.name = "Name 1"

var m2 = MenuItems()
m2.id = "2"
m2.name = "Name 2"

var m3 = MenuItems()
m3.id = "3"
m3.name = "Name 3"

var allMenuItems: [MenuItems] = [m1, m2, m3] // [{id "1", name "Name 1"}, {id "2", name "Name 2"}, {id "3", name "Name 3"}]

var anArrayOfIds: [String] = ["1", "3"]

The filtered output would be:

var filteredMenuItems: [MenuItems] = [m1, m3] // [{id "1", name "Name 1"}, {id "3", name "Name 3"}]

Any suggestions?

2
  • 1
    var id: String, self.id = "", This is really bad practice in Swift. Don't add mutability where it's not needed, and don't use non-sensical defaults (a name of "") Commented Dec 5, 2018 at 21:37
  • @Alexander - point taken, thanks. This is not the actual code in use. Commented Dec 5, 2018 at 21:55

4 Answers 4

2

How about

let filteredMenuItems = allMenuItems.filter { anArrayOfIds.contains($0.id)}

That gives me the items with 1 and 3.

I've taken the liberty of updating your code a little:

struct MenuItems {
    let id: String
    let name: String
}

let m1 = MenuItems(id: "1", name: "Name 1")
let m2 = MenuItems(id: "2", name: "Name 2")
let m3 = MenuItems(id: "3", name: "Name 3")

let allMenuItems = [m1, m2, m3]
let anArrayOfIds: [String] = ["1", "3"]

let filteredMenuItems = allMenuItems.filter { anArrayOfIds.contains($0.id)}

Hope that helps

Sign up to request clarification or add additional context in comments.

Comments

2

You could do it like so:

let filteredMenuItems = allMenuItems.filter { anArrayOfIds.contains($0.id) }

I would suggest you :

  • remove the pointless initializer,
  • make id an integer,
  • if the properties won't be changed after initialization then use let instead of var,
  • make anArrayOfIds a set instead of an array, since the contains method would be O(1) instead of O(n).

Implementing all of these recommendations gives you the following code:

struct MenuItems {
    let id: Int
    let name: String
}

let m1 = MenuItems(id: 1, name: "Name 1")
let m2 = MenuItems(id: 2, name: "Name 2")
let m3 = MenuItems(id: 3, name: "Name 3")

let allMenuItems: [MenuItems] = [m1, m2, m3]

var aSetOfIds: Set<Int> = [1, 3]  //I used a var if aSetOfIds could be changed

var filteredMenuItems = allMenuItems.filter { aSetOfIds.contains($0.id) }

1 Comment

As mentioned, this was drafted in a hurry and I've already taken a bashing for it. The id is actually a GUID, and none of this code is actually real per se. Still I guess I will pay in downvotes. Thanks for your response.
1

You can use filter and contains

let filtered = allMenuItems.filter( { anArrayOfIds.contains($0.id) })

Comments

1

First of all please don't use a weird syntax in a struct like

init() {
     self.id = ""
     self.name = ""
}

Delete the init method and create items with the implicit memberwise initializer, by the way you should name structs representing a single object in singular form:

let m1 = MenuItem(id: "1", name: "Name 1")

You can even declare the members as constants

struct MenuItem {
    let id, name : String
}

And don't annotate types the compiler can infer.


Filter the array by another array of id values with

let filteredMenuItems = allMenuItems.filter{ anArrayOfIds.contains($0.id) }

1 Comment

Yes, apologies. This isn't the actual code and was clubbed together in a hurry. Still, no excuse on my part.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.