动态类的Swift映射/过滤?

时间:2018-01-29 13:22:30

标签: swift

我正在尝试按其变量类型过滤对象数组。节点是一个具有位置的对象,但以不同的方式定义 - 作为点,矢量或附件。这是一个代码:

let product = products[(tas as NSIndexPath).row]

在最后一行,我收到了一条消息class Joint { var position:Position init(_ position:Position) { self.position = position } } class Position { var point:Point { return Point (0,0) } } class Point: Position { //Something different } class Vector:Position { //Something different } class Attachment : Position { //Something different } let content : [Joint] = [Joint(Vector()), Joint(Vector()), Joint(Attachment()), Joint(Point()), Joint(Point()) ] let positionTypes:[Position.Type] = [Point.self, Attachment.self, Vector.self] let points :[Position] = content.filter{$0.position is Point}.map{$0.position as! Point} Swift.print(points) // OK, prints: [__lldb_expr_148.Point, __lldb_expr_148.Point] let attachments :[Position] = content.filter{$0.position is Attachment}.map{$0.position as! Attachment} Swift.print(attachments) // OK, prints: [__lldb_expr_148.Attachment] let vectors :[Position] = content.filter{$0.position is Vector}.map{$0.position as! Vector} Swift.print(vectors) // OK, prints: [__lldb_expr_148.Vector, __lldb_expr_148.Vector] for positionType in positionTypes { Swift.print (positionType, type(of:positionType)) // if the next line does not exist loop returns: // Point Position.Type // Attachment Position.Type // Vector Position.Type // This line doesn't work: let positions:[Position] = content.filter{$0.position is positionType}.map{$0.position as! positionType} }

如何让最后一行工作?

2 个答案:

答案 0 :(得分:2)

这不是正确的方法:

let points :[Position] = content.filter{$0.position is Point}.map{$0.position as! Point}

这里正确的工具是flatMap

let points: [Position] = content.flatMap { $0.position as? Point }

as?施放并非真正必要。 .position始终是Position;没有必要把它投入任何东西。所以你也可以这样做:

let points: [Position] = content.map { $0.position }.filter { $0 is Point }

该模式允许您执行您在最后一步中尝试执行的操作。映射到.position,然后过滤类型。

let positions:[Position] = content
    .map { $0.position }
    .filter { type(of: $0) == positionType }
}

答案 1 :(得分:0)

虽然你可以沿着这条路走下去,你考虑过使用enum吗?因为您想要在数组中表示多种类型的数据。

e.g。

//: Playground - noun: a place where people can play

import Cocoa

protocol Position {
    var point: Point { get }
}

enum PositionType {
    case point
    case vector
    case attachment
}

enum Joint {

    case point(Point)
    case vector(Vector)
    case attachment(Attachment)

    var position: Position {
        switch self {
        case .point(let position):
            return position
        case .vector(let position):
            return position
        case .attachment(let position):
            return position
        }
    }

    var positionType: PositionType {
        switch self {
        case .point:
            return .point
        case .vector:
            return .vector
        case .attachment:
            return .attachment
        }
    }

    func isPositionType(_ positionType: PositionType) -> Bool {
        return self.positionType == positionType
    }

}

class Point: Position {
    var point: Point { return self }
}

class Vector:Position {
    var point: Point { return Point() }
}

class Attachment : Position {
    var point: Point { return Point() }
}

let content: [Joint] = [.vector(Vector()), .vector(Vector()), .attachment(Attachment()), .point(Point()), .point(Point()) ]

// for-in syntax

for case .point(let point) in content {
    print("Point", point)
}

for case .vector(let vector) in content {
    print("Vector", vector)
}

for case .attachment(let attachment) in content {
    print("Attachment", attachment)
}

// using PositionType to filter

let positionTypes: [PositionType] = [ .point, .vector, .attachment ]

for positionType in positionTypes {
    let positions = content.filter { $0.isPositionType(positionType) }
}

// using filter

let points = content.filter {
    $0.positionType == .point
}

let vectors = content.filter {
    $0.positionType == .vector
}

let attachments = content.filter {
    $0.positionType == .attachment
}