Как отфильтровать объекты определенного типа из массива [AnyObject] - PullRequest
0 голосов
/ 17 января 2019

Можно ли отфильтровать массив [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 голосов
/ 17 января 2019

Я думаю, вы могли бы использовать что-то вроде этого ...

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)

Но я не уверен, что еще вы получаете от этого, в первую очередь от фильтрации по строке?

...