8

The ForEach struct in swiftUI is really useful for iterating over an array to create views, but I'm wondering if there is a way to iterate over multiple arrays at the same time. I know that if you use zip when you are using a for in loop you can achieve this like:

for (height, label) in zip(heights, labels) {
print("\(height) : \(label)")}

However, i'm wondering if it's possible to do this with a ForEach. I have tried, but I can't seem to get it right. The only way i've found to iterate over two arrays is to use an index to subscript each array, but that doesn't seem swifty enough.

What i've tried so far is:


let heights:[CGFloat] = [20, 40, 100, 5, 70, 80, 30]
let labels = ["mon", "tue", "wed", "thu", "fri", "sat", "sun", ]

ForEach(zip(heights, labels), id: \.self) { (height, label) in
                    Text("\(height)")
                    Text(label)
                }

But no joy, and the swiftUI errors are as cryptic as ever..... Any pointers gratefully received.

Edit: One way of getting it working that I have found is to do a nested ForEach, like:

ForEach(self.heights, id: \.self) { height in
                    Group {
                        Text("\(height)")
                        ForEach(self.labels, id: \.self) { label in

                            Text(label)
                        }
                    }
                }

But again, it doesn't seem very swifty.

2
  • Which is the error that you're getting from SwiftUI? Commented Feb 3, 2020 at 16:32
  • 1
    It's completely off the mark. It's saying: Generic parameter 'Background' could not be inferred. I know that it has nothing to do with the actual problem, the compiler errors are just whack atm with swiftUI. Commented Feb 3, 2020 at 16:32

1 Answer 1

31

Here is possible approach (tested & worked with Xcode 11.3.1)

ForEach(Array(zip(heights, labels)), id: \.0) { item in
    VStack {
        Text("\(item.0)")
        Text(item.1)
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

Top man! using the id: \.0 was the trick then. Can you explain why this works and not \.self?
id here is expected as keypath to Hashable property, but \.self in this case is tuple, while \.0 is CGFloat. The \.1 also can be used. In any case you have to provide something Hashable.
Makes sense! Thanks for taking the time to answer my question.
This is really good. But what if I have 3 arrays? How to solve in this case when zip works with only two sequences?
@ShawkathSrijon a bit late, but you can either do zip(a, zip(b, c)) or some github project like gist.github.com/tailec/bf37d064df79e5121def6fafbf1148b1 If you don't like the manual solution of multiple nested zips, you can always unbox them with a map. This will eliminate nested tuples: zip(a, zip(b, c)).map { ($0, $1.0, $1.1) }

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.