0

Here is my code, and I'm wondering how can I allow all 4 arrays to be used in the ForEach statement as right now I can only use 2.

struct ContentView: View {
var array1 = ["1", "2", "3"]
var array2 = ["a", "b", "c"]
var array3 = ["!", "@", "#"]
var array4 = ["+", "-", "~"]
      var body: some View {
                  VStack {
            HStack {
            Text("Upcoming Flights")
                    .font(.title2)
                .fontWeight(.bold)
            Spacer()
            }
            ScrollView(.horizontal) {
                HStack {
                    ForEach(Array(zip(array1, array2)), id: \.0) { item in
                    VStack {
                        Group {
                            Text("Flight")
                            Text(item.0)
                                .padding(.bottom)
                                .font(.caption)
                                .foregroundColor(.gray)
                            Text("Instructor")
                            Text(item.1)
                                .font(.caption)
                                .foregroundColor(.gray)
                        }
                    }
                    .frame(width: 110, height: 140)
                    .overlay {
                        RoundedRectangle(cornerRadius: 10)
                            .stroke(.gray.opacity(0.3), lineWidth: 1)
                    }
                    Spacer()
                    }
                }
                .frame(height: 200)
            }
            .frame(height: 200)
            .offset(y: -25)
        }
            .offset(y: -10)
            .padding([.leading, .trailing, .bottom])
     }
 }

Thanks in advance. @jnpdx I hope this helps, and I made sure it was reproducible. I don't want the arrays combined, but set as Text, like the first two arrays all in the same Stack in the view.

user17864647
  • 322
  • 2
  • 14
  • Unfortunately, you haven't included enough information to debug the issue you're encountering. For example, what type(s) are `ScheduledAirplane`, `ScheduledInstructor`, etc? Are they all the *same* type? What errors are you encountering? Can you include a [mre] to help this get debugged? – jnpdx Jan 08 '22 at 04:19
  • Sorry, first question, thanks for the comment. All of them (ScheduledAirplane, ScheduledInstructor, ScheduledTime, ScheduledDate) are Arrays of data taken from Firebase. The goal is to Display all this information in repeating VStacks, with different information from each of the Arrays. Right now, I've got just ScheduledFlights and ScheduledInstructors, which works perfectly fine. The error I'm getting is "Extra arguments at positions #3, #4 in call" which is obvious as I realize only two variables are allowed in a zip, from the link in the Q. I hope this is all you need. – user17864647 Jan 08 '22 at 04:39
  • There are many possibilities [here](https://stackoverflow.com/questions/25146382/how-do-i-concatenate-or-merge-arrays-in-swift). Do any of those answer your question? – jnpdx Jan 08 '22 at 04:41
  • I guess that could be a solution, but how is it possible to list it together. The goal is to have something like: Instructor: _________ Airplane: _________ Date: ________ Time: __________ All in seperate Vstacks inside a scrollview ForEach statement. Kinda confusing, sorry. – user17864647 Jan 08 '22 at 04:58
  • You haven't included any information about your models, so I don't know the specifics about your views. It seemed to me that the crux of your question is how to combine multiple arrays -- the question I linked to listed many different ways of doing that (other than `zip`). Did you try any of them? – jnpdx Jan 08 '22 at 04:59
  • My bad, I'll try some of them now and see if I can figure something out. – user17864647 Jan 08 '22 at 05:03
  • The problem with combining the arrays leads to me trying to figure out how to extract them again. I can't just use a ForEach statement for the combined Array, because then all the Data will be split up each into its own Vstack, rather than the four variables being together in one. – user17864647 Jan 08 '22 at 05:09
  • Oh, okay, I think *maybe* I'm getting what you're after. Perhaps you want [this](https://stackoverflow.com/questions/40517760/is-there-a-zip-function-to-create-tuples-with-more-than-2-elements) – jnpdx Jan 08 '22 at 05:14
  • Looks good, but one question, wouldn't I need a ForEach statement if I want to have the arrays split up and such or does For work fine. – user17864647 Jan 08 '22 at 05:18
  • I don't know what that means. I didn't suggest not using `ForEach`. I'm trying to answer your question about combining the arrays within the `ForEach`. I don't know what "split up and such" is referring to. If you need more assistance, the best route forward would be to include a [mre] where someone can give a concrete answer. – jnpdx Jan 08 '22 at 05:20
  • I edited the question to try and give a better example. Hopefully it can help, if not, I'll try to continue on giving information. – user17864647 Jan 08 '22 at 05:29
  • What you've included is not a [mre] -- check out the link and see what's involved. Basically, it should be something that someone else can run, including the important parts to demonstrate the issue, and nothing else. Your code is missing lots of code and can't be compiled as is. How about including a sample view with data preloaded (the part of loading it from Firebase is irrelevant) that can be pasted into Xcode? Then, describe how the output you're getting is different from what you expect. – jnpdx Jan 08 '22 at 05:31
  • Hopefully that works. I'll keep you updated if needed. – user17864647 Jan 08 '22 at 05:43
  • It seems that you extract arrays from records which contain the information of one item respectively . **Don't do this**. Model the records to structs then you have only one object in the loop. Multiple arrays as data source are a horrible practice. – vadian Jan 08 '22 at 06:03
  • @user17864647 I concur with the above (see the bottom part of my answer) – jnpdx Jan 08 '22 at 06:53
  • Thanks for all the help, I'll make sure to look into it. – user17864647 Jan 08 '22 at 18:45

1 Answers1

0

With the way your data is currently structured, you could zip the arrays together into a multi-layered tuple and then extract the values. It's a little ugly.

struct ContentView: View {
    var array1 = ["1", "2", "3"]
    var array2 = ["a", "b", "c"]
    var array3 = ["!", "@", "#"]
    var array4 = ["+", "-", "~"]
    
    var arraysForLoop : [(String,String,String,String)] {
        let result = zip(array1,zip(array2,zip(array3,array4)))
        return result.map { ($0.0, $0.1.0, $0.1.1.0, $0.1.1.1) }
    }
    
    var body: some View {
        VStack {
            HStack {
                Text("Upcoming Flights")
                    .font(.title2)
                    .fontWeight(.bold)
                Spacer()
            }
            ScrollView(.horizontal) {
                HStack {
                    ForEach(arraysForLoop, id: \.0) { item in
                        VStack {
                            Group {
                                Text("Flight")
                                Text(item.0)
                                    .padding(.bottom)
                                    .font(.caption)
                                    .foregroundColor(.gray)
                                Text("Instructor")
                                Text(item.1)
                                    .font(.caption)
                                    .foregroundColor(.gray)
                                Text(item.2)
                                Text(item.3)
                            }
                        }
                        .frame(width: 110, height: 140)
                        .overlay {
                            RoundedRectangle(cornerRadius: 10)
                                .stroke(.gray.opacity(0.3), lineWidth: 1)
                        }
                        Spacer()
                    }
                }
                .frame(height: 200)
            }
            .frame(height: 200)
            .offset(y: -25)
        }
        .offset(y: -10)
        .padding([.leading, .trailing, .bottom])
    }
}

My suspicion is that long-term, you will decide that your current method of storing the data (eg multiple arrays of non-ID'd data) won't be an ideal structure. For instance, what if one array changes and the others don't? If the indexes change, all your data will be offset.

I'd recommend storing your data in one array where each item has each field you need (Instructor, Airplane, etc) -- this will make things much easier for you.

jnpdx
  • 45,847
  • 6
  • 64
  • 94