Redwood
Redwood

Reputation: 69322

How do I turn an array of nullable items into a nullable array based on whether any of the items are null?

I have an array of nullable items which may or may not have any nils in it:

let source = [1, 2, 3] as [Int?]
// or
let source = [1, 2, nil] as [Int?]

I want to turn it into an [Int]? with the values as Ints if no items are nil or nil if any item is nil.

What's the idiomatic way to do this?

Things I've tried:

// fails with: fatal error: can't unsafeBitCast between types of different sizes 
let result = source as? [Int]

and:

func toNonNullable<T>(array: [T?]) -> [T]? {
    if array.filter({$0 == nil}).count != 0 {
        return nil;
    }

    return array.map({$0!}) 
}

// This works, but seems likey to be non-idiomatic (as well as being ineffecient). 
let result = toNonNullable(source)

Upvotes: 0

Views: 1390

Answers (1)

matt
matt

Reputation: 535766

Here's how I would write it:

let source = [1, 2, nil] as [Int?]
var result : [Int]? = {
    for i in source {
        if i == nil {
            return nil
        }
    }
    return source.map {$0!}
}()

But that doesn't really meet your "inefficient" consideration. Someone has to look through the array to see if it contains nil, so nothing is lost by looping and doing that; but the inefficiency is that we loop twice, because map is a loop. If you really hate that, here's a way out:

var result : [Int]? = {
    var temp = [Int]()
    for i in source {
        if let i = i {
            temp.append(i)
        } else {
            return nil
        }
    }
    return temp
}()

Lots of very idiomatic Swifties in those formulations, I think!

Upvotes: 3

Related Questions