如何从[AnyObject]数组中过滤某些类型的对象

时间:2019-01-17 13:44:00

标签: swift filter anyobject

是否可以过滤[AnyObject]数组以产生给定类型的所有元素,而没有别的?

如果在编译时知道类型,我可以这样做:

class MyClass1: CustomStringConvertible {

    var value: Int

    var description: String {
        return "MyClass1: \(value)"
    }

    init(_ value: Int) {
        self.value = value
    }
}

class MyClass2: CustomStringConvertible {

    var value: Int

    var description: String {
        return "MyClass1: \(value)"
    }

    init(_ value: Int) {
        self.value = value
    }
}

class MySubClass1: MyClass1 {
    override var description: String {
        return "MySubClass1: \(value)"
    }
}

let a1 = MySubClass1(1)
let a2 = MySubClass1(2)
let b1 = MyClass1(3)
let b2 = MyClass2(4)

let array: [AnyObject] = [a1, b1, a2, b2]

func getClass1ObjectsFromArray(_ array: [AnyObject]) -> [MyClass1] {
    return array.compactMap( { $0 as? MyClass1 })
}

func getSubClass1ObjectsFromArray(_ array: [AnyObject]) -> [MySubClass1] {
    return array.compactMap( { $0 as? MySubClass1 })
}

print(getClass1ObjectsFromArray(array))

print(getSubClass1ObjectsFromArray(array))

打印:

[MySubClass1: 1, MyClass1: 3, MySubClass1: 2]
[MySubClass1: 1, MySubClass1: 2]

对于每种要过滤的类型,我必须编写一个单独的函数。在我看来,这很丑陋,并且只有在运行时才知道要选择的类型,这是行不通的。

问题:

是否有编写这种功能的通用方法?最好是这样的:

func getObjectsOfType(_ type: TypeExpression, fromArray array: [AnyObject])
 -> [TypeExpression] {
     ... 
    }

或通过其他任何方式实现这一目标?

感谢您的帮助!

1 个答案:

答案 0 :(得分:5)

我认为您可以使用类似这样的东西...

let filteredArray = array.compactMap { $0 as? RequiredType }

这将过滤数组并返回仅包含所需类型的类型化数组。

注意

话虽如此。在Swift中,应尽可能避免使用异构数组。数组实际上应该只包含一种类型的项目。

一些代码测试...

在操场上经过测试...

let array: [Any] = [1, "hello", 3, 3.1415, "world"]

let filteredArray = array.compactMap { $0 as? String }

filteredArray

输出:

filteredArray = ["hello", "world"]

编辑1

您还可以创建一个类似这样的通用函数...

func filter<T>(array: [Any]) -> [T] {
    return array.compactMap { $0 as? T }
}

let filteredArray: [String] = filter(array: array)

然后将根据所需的输出数组的类型进行过滤。

我不确定仅在运行时知道所需的类型是什么意思。您能举一个具体的例子吗?

编辑2

另一种可能性是像这样的通用函数...

func filter<T>(array: [Any], byType typeObject: T) -> [T] {
    return array.compactMap { $0 as? T }
}

let filteredArray = filter(array: array, byType: "some string")

这使用第二个参数的类型信息按该类型的项过滤数组。

编辑3

如果您不喜欢传递类型的实例,则可以传递类型本身...

func filter<T>(array: [Any], byType typeObject: T.Type) -> [T] {
    return array.compactMap { $0 as? T }
}

let filteredArray = filter(array: array, byType: String.self)

但是我不确定除了从头开始按字符串过滤之外,您还能从中得到什么?