Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

SwiftUI: Find element position in array

I’m still trying to get my head around Swift/SwiftUI, so apologies for what’s likely a really simple question. Consider this simple SwiftUI file:

import SwiftUI

struct sampleStruct {
    let entryID: Int // comes from the system
    let name: String
}


struct TestView: View {
    
    var listEntries = [sampleStruct(entryID: 301, name: "Pete"),
                       sampleStruct(entryID: 5003, name: "Taylor"),
                       sampleStruct(entryID: 13, name: "Suzie")]
    
    var body: some View {
        VStack{
            ForEach(listEntries, id: \.entryID) { idx in
                Text(idx.name)
            }
        }
    }
}

struct TestView_Previews: PreviewProvider {
    static var previews: some View {
        TestView()
    }
}

Here’s my question: I’m looking for a simple way to add the position of the element in the array to the text field. I.e. instead of Pete, Taylor, Susie, I’d like to get:

1 Pete

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

2 Taylor

3 Suzie

I thought that this could do the trick:

...
VStack{
            ForEach(listEntries, id: \.entryID) { idx in
                Text( listEntries.firstIndex { $0.id == idx.entryID } )
                Text(idx.name)
            }
        }
...

But, I’m getting the error "No exact matches in call to initializer".

Any help would be appreciated,

Philipp

>Solution :

The simplest approach would be to use enumerated(), which returns a sequence of pairs (index and item):

struct TestView: View {
    
    var listEntries = [sampleStruct(entryID: 301, name: "Pete"),
                       sampleStruct(entryID: 5003, name: "Taylor"),
                       sampleStruct(entryID: 13, name: "Suzie")]
    
    var body: some View {
        VStack{
            ForEach(Array(listEntries.enumerated()), id: \.1.entryID) { (index,item) in
                Text("\(index + 1) \(item.name)")
            }
        }
    }
}

Note that for extremely large collections you might want a different approach for performance reasons, but for anything reasonably sized, this will work well. A quick and easy upgrade to it would be to used indexed() from Swift Algorithms in place of .enumerated() (you could omit the Array(...) wrapper if you did this as well.


If for learning purposes you want to see what you’d have to do to adjust your original approach, you’d want to:

  1. Use .entryID instead of .id, which doesn’t exist on your model
  2. Provide a default index in case firstIndex returns nil
  3. Interpolate the result into a String

One solution might look like this:

struct TestView: View {
    
    var listEntries = [sampleStruct(entryID: 301, name: "Pete"),
                       sampleStruct(entryID: 5003, name: "Taylor"),
                       sampleStruct(entryID: 13, name: "Suzie")]
    
    var body: some View {
        VStack{
            ForEach(listEntries, id: \.entryID) { item in
                let index = listEntries.firstIndex { $0.entryID == item.entryID } ?? -1
                Text("\(index + 1) \(item.name)")
            }
        }
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading