0

Is it possible in Swift to have interpolation of property (variable) names from the content of other properties? In the code segment below, In the first for loop I would like to set the property eachItem to the item name contained in the rotation array. Then in the second inner for loop I want to iterate through the array named by what is in the eachItem property.

var groupA = ["groupA1", "groupA2", "groupA3"]
var groupB = ["groupB1", "groupB2", "groupB3", "groupB4", "groupB5", "groupB6"]
var groupC = ["groupC1", "groupC2", "groupC3", "groupC4", "groupC5"]

var rotation = ["groupA", "groupB", "groupC"]

for eachGroup in rotation {
  for eachItem in \(eachGroup) {
    print(eachItem)
  }
}

The iterations through the two for loops would give us:

eachGroup = "groupA"
  eachItem = "groupA1"
  eachItem = "groupA2"
  eachItem = "groupA3"
eachGroup = "groupB"
  eachItem = "groupB1"
  eachItem = "groupB2"
  eachItem = "groupB3"
  eachItem = "groupB4"
  eachItem = "groupB5"
  eachItem = "groupB6"
eachGroup = "groupC"
  eachItem = "groupC1"
  eachItem = "groupC2"
  eachItem = "groupC3"
  eachItem = "groupC4"
  eachItem = "groupC5"

Is variable/property name interpolation possible in Swift? If so, how can I do that?

Additionally, is it better to handle this using a two-dimensional array? If so, how would I do that?

Michael Sheaver
  • 2,059
  • 5
  • 25
  • 38

3 Answers3

0

You might want a dictionary and not an array. Why not just do something like:

var rotation = [groupA, groupB, groupC]

You can also use flatMap on an array of arrays like that.

Patrick Tescher
  • 3,387
  • 1
  • 18
  • 31
0

Using a 2D-String array, with the same nested for .. in loop as in you example:

var groupA : [String] = ["groupA1", "groupA2", "groupA3"]
var groupB : [String] = ["groupB1", "groupB2", "groupB3", "groupB4", "groupB5", "groupB6"]
var groupC : [String] = ["groupC1", "groupC2", "groupC3", "groupC4", "groupC5"]

var rotation : [[String]] = [groupA, groupB, groupC]

for eachGroup in rotation {
    for eachItem in eachGroup {
        print(eachItem)
    }
}

For the sake of technical discussion, you can interpolate over property names, by making use of runtime introspection and foundation class NSObject. Now, I can't see anyone ever actually resorting to this as it is non-Swifty in ways I can't ... (so don't), but note that it can be done:

class Container : NSObject {
    let dummyArr : [String] = []
    let groupA : [String] = ["groupA1", "groupA2", "groupA3"]
    let groupB : [String] = ["groupB1", "groupB2", "groupB3", "groupB4", "groupB5", "groupB6"]
    let groupC : [String] = ["groupC1", "groupC2", "groupC3", "groupC4", "groupC5"]

    init(_ rotation: [String]) {
        super.init()

        let a = Mirror(reflecting: self).children.filter { $0.label != nil }
        for eachGroup in a where eachGroup.label != "dummyArr" {
            print("eachGroup: \(eachGroup.label ?? "")")
            let b = self.valueForKey(eachGroup.label ?? "dummyArr")
            if let eachGroup = b as? [String] {
                for eachElement in eachGroup {
                    print("\teachElement = \(eachElement)")
                }
            }
        }
    }
}

var rotation = ["groupA", "groupB", "groupC"]
let _ = Container(rotation)

Prints output:

/*  eachGroup: groupA
        eachElement = groupA1
        eachElement = groupA2
        eachElement = groupA3
    eachGroup: groupB
        eachElement = groupB1
        eachElement = groupB2
        eachElement = groupB3
        eachElement = groupB4
        eachElement = groupB5
        eachElement = groupB6
    eachGroup: groupC
        eachElement = groupC1
        eachElement = groupC2
        eachElement = groupC3
        eachElement = groupC4
        eachElement = groupC5   */
dfrib
  • 70,367
  • 12
  • 127
  • 192
  • This did work, although you don't need to explicitly type the properties since type inference works great here. In fact, for best practice, the Swift documentation recommends that you not explicitly declare property types unless Swift cannot insert the type from he code. – Michael Sheaver Jan 28 '16 at 18:57
  • @SillyGoof I added the explicit types here to shed extra light (to OP) on how arrays of strings are put as members into an array of string arrays, but it's good that you point it out so readers don't infer this as a necessity, thanks. – dfrib Jan 28 '16 at 18:59
  • I do appreciate this deep dive into interpolation. Now, this begs the question: if it is possible to do interpolation of property names in Objective-C, albeit extremely messy, I wonder if they can build a bridge so we can do it is an easy, Swift-y manner? – Michael Sheaver Jan 28 '16 at 19:20
  • @SillyGoof This is just off the top of my head, but I would assume: no. It kind of circumvents the renowned type safety of Swift: even if we could make it somewhat type safe using optional binding (w.r.t. trying to access properties that don't exist) we're leaving ourself open to undefined behaviour. I would personally never (ab-?)use dynamic property inspection in this manner in some actual software of mine. But hey, we never know :0) – dfrib Jan 28 '16 at 19:25
  • You know, now that you bring up type safety, I agree that it probably is not a good idea to allow property name interpolation. Thanks for pointing that out! – Michael Sheaver Jan 28 '16 at 19:33
  • @SillyGoof Happy to help! – dfrib Jan 28 '16 at 19:36
0

Many thanks to all three of you for your quick help! :)

For others who might want to know, my final code is below:

var groupA = ["groupA1", "groupA2", "groupA3"]
var groupB = ["groupB1", "groupB2", "groupB3", "groupB4", "groupB5", "groupB6"]
var groupC = ["groupC1", "groupC2", "groupC3", "groupC4", "groupC4"]

var rotation = [groupA, groupB, groupC]

for eachGroup in rotation {
  for eachItem in eachGroup {
    print(eachItem)
  }
}

As for the original question about property name interpolation, it does not appear to be possible in Swift, probably (and wisely so) due to their emphasis on type safety.

Michael Sheaver
  • 2,059
  • 5
  • 25
  • 38