Quick test: no peeking #swiftlang

It’s actually quite an interesting case.

This seems to be fixed in the latest beta unless I’m messing this up, which is always a likely case: You can’t coerce this [NSObject] array to [Any] by assignment. The following declaration

var inputArray : [Any] = [1, 2, 3, [4, 5, [6,7,8]]]

fails with error: ‘Int’ is not convertible to ‘IntegerLiteralConvertible’.  I should point out that you can intersperse type casts within the array, as Mike Ash showed me. This is a legal assignment:

var inputArray: [Any] = [1, 2, 3, [4, [5,9], [6,7,8]] as [Any]]

and this:

var inputArray: [Any] = [1, [2, [8]] as [Any], 3, [4, [5,9], [6,7,8]] as [Any]]

As you see, as complexity increases so do the casting requirements.

All this came up because someone popped into #swift-lang asking how to flatten the initial [1, 2, 3, [4, 5, [6, 7, 8]]] array. You’d think this would be a perfect example of flatMap but it’s really not due to the type issues.

What I came up with (without a huge amount of investment, so I’m sure there are better solutions) is the following. Its inelegance speaks to type safety.

import Foundation
func NSFlatten(inputArray : [NSObject]) -> [NSObject] {
    var workingArray = inputArray
    repeat {
        var tmp : [NSObject] = []
        workingArray.forEach({
            if let array = $0 as? NSArray {
                tmp.extend(array as! [NSObject])
            } else {
                tmp.append($0)
            }
        })
        workingArray = tmp
    } while workingArray.map({$0 is NSArray}).contains(true)
    return workingArray
}

3 Comments

  • what about crash?

  • Sadly, I am still using Xcode 6.3.1 for ineffable production reasons, however this more elegant solution worked for me. I’d appreciate your feedback if it could be better (including safer).

    let a = [[1, 2, 3, [4, 5, [6,7,8]]
    let b = [[1, 2, 3, [4, [5,9], [6,7,8]]
    let c = [1, 2, 3, 4, 5]
    import Foundation
    func NSFlatten(inputArray : [NSObject]) -> [NSObject] {
        var result = [NSObject]()
        for item in inputArray {
            if let array = item as? [NSObject] {
                    result += NSFlatten(array)
            } 
            else {
                    result.append(item)
            }
        }
        return result
    }
    NSFlatten(a)  // [1, 2, 3, 4, 5, 6, 7, 8]
    NSFlatten(b)  // [1, 2, 3, 4, 5, 9, 6, 7, 8]
    NSFlatten(c)  // [1, 2, 3, 4, 5]
    • Nice, thanks!