如何在Swift中解包数组元素? (即Array <int?> as Array <int>)</int> </int?>

时间:2014-08-06 15:00:01

标签: ios swift

假设我有一个String数组,我想将它映射到一个Int数组 我可以使用map函数:

var arrayOfStrings: Array = ["0", "a"]
let numbersOptional = arrayOfStrings.map { $0.toInt() }
// numbersOptional = "[Optional(0), nil]"

Numbers现在是一个Int?数组,但我想要一个Int数组。 我知道我可以这样做:

let numbers = arrayOfStrings.map { $0.toInt() }.filter { $0 != nil }.map { $0! }
// numbers = [0]

但这似乎并非迅速。从Int数组转换?对于Array of Int,需要使用相当多的样板函数来调用filter和map。有更快捷的方法吗?

5 个答案:

答案 0 :(得分:6)

更新:从Swift 1.2开始,有一个内置的flatMap数组方法,但它不接受Optional s,所以下面的帮助程序仍然是是有用的。


我喜欢使用辅助flatMap函数来处理这类事情,就像Scala对集合的flatMap方法一样(可以将Scala Option视为0或1的集合元素,粗略地说):

func flatMap<C : CollectionType, T>(source: C, transform: (C.Generator.Element) -> T?) -> [T] {
    var buffer = [T]()
    for elem in source {
        if let mappedElem = transform(elem) {
            buffer.append(mappedElem)
        }
    }
    return buffer
}

let a = ["0", "a", "42"]
let b0 = map(a, { $0.toInt() }) // [Int?] - [{Some 0}, nil, {Some 42}]
let b1 = flatMap(a, { $0.toInt() }) // [Int] - [0, 42]

flatMap的这个定义是Optional更为一般flatMap应该做的事情的一个特例:

func flatMap<C : CollectionType, T : CollectionType>(source: C, transform: (C.Generator.Element) -> T) -> [T.Generator.Element] {
    var buffer = [T.Generator.Element]()
    for elem in source {
        buffer.extend(transform(elem))
    }
    return buffer
}

我们得到的地方

let b2 = flatMap(a, { [$0, $0, $0] }) // [String] - ["0", "0", "0", "a", "a", "a", "42", "42", "42"]

答案 1 :(得分:5)

使用reduce构建新数组可能更具惯用性

func filterInt(a: Array<String>) -> Array<Int> {
    return a.reduce(Array<Int>()) {
        var a = $0
        if let x = $1.toInt() {
            a.append(x)
        }
        return a
    }
}

实施例

filterInt(["0", "a", "42"]) // [0, 42] 

您真正想要的是collectmap + filter)方法。鉴于您需要应用特定的过滤器,在这种情况下甚至可以使用flatMap(参见Jean-Philippe的回答)。太糟糕了,swift标准库没有提供这两种方法。

答案 2 :(得分:2)

没有很好的内置Swift标准库方法来做到这一点。但是,Haskell有一个函数mapMaybe,可以完成您正在寻找的函数(假设您只想抛弃nil值)。这是Swift中的等价物:

func mapSome<S: SequenceType, D: ExtensibleCollectionType>
  (source: S, transform: (S.Generator.Element)->D.Generator.Element?)
  -> D {
        var result = D()
        for x in source {
            if let y = transform(x) {
                result.append(y)
            }
        }
        return result
}

// version that defaults to returning an array if unspecified
func mapSome<S: SequenceType, T>
  (source: S, transform: (S.Generator.Element)->T?) -> [T] {
    return mapSome(source, transform)
}

let s = ["1","2","elephant"]
mapSome(s) { $0.toInt() }  // [1,2]

答案 3 :(得分:2)

更新: Xcode 7.2•Swift 2.1.1

let arrayOfStrings = ["0", "a", "1"]
let numbersOnly = arrayOfStrings.flatMap { Int($0) }

print(numbersOnly)   // [0,1]

答案 4 :(得分:1)

您可以考虑使用reduce,它更灵活:

var arrayOfStrings: Array = ["0", "a"]
let numbersOptional = arrayOfStrings.reduce([Int]()) { acc, str in
  if let i = str.toInt() {
    return acc + [i]
  }

  return acc
}