Swift地图和过滤器:查找不属于给定玩家的所有工厂

时间:2017-07-28 14:08:28

标签: arrays swift filtering reducers

我有一个Swift playground文件,其中有一个带有子实体的工厂列表,称为引擎;玩家可以拥有多个引擎

因此关系;

Factory -> Engine <- Player

  • 一家工厂有很多引擎
  • 一名玩家有很多引擎
  • 一个引擎有一个父(工厂)
  • 一个引擎有一个所有者(玩家)

我正在尝试构建一个Swift地图并过滤其中,它会生成一个列表,其中包含给定玩家对象 所拥有的所有工厂。

我的代码现在如下;

//: Swift Playground code
import Foundation

class Factory : CustomStringConvertible {
    var name: String = ""
    var engines: [Engine] = [Engine]()
    var description: String {
        return self.name
    }

    var owners: [Player]? {
        let filtered = self.engines.filter { (eng:Engine) -> Bool in
            return (eng.owner != nil)
            }
            .sorted { (engA:Engine, engB:Engine) -> Bool in
                return ((engA.owner?.turnOrder)! < (engB.owner?.turnOrder)!)
            }.flatMap { (eng:Engine) -> Player? in
                return (eng.owner)
        }

        return filtered
    }

    init(name: String) {
        self.name = name

        // create 3 children (engines)
        for _ in 1...3 {
            let engine = Engine.init(parent: self)
            self.engines.append(engine)
        }
    }
}

class Engine : CustomStringConvertible {
    weak var parent: Factory?
    weak var owner: Player?

    var description: String {
        guard let hasParent = self.parent else {
            return "N/A"
        }
        return ("\(hasParent.name) - engine")
    }

    init(parent: Factory) {
        self.parent = parent
    }

    func setOwner(owner: Player) {
        self.owner = owner
        self.owner?.addEngine(engine: self)
    }
}

class Player : CustomStringConvertible {
    var name: String = ""
    var engines: [Engine] = [Engine]()
    var turnOrder: Int = 0
    var description: String {
        return self.name
    }

    init(name: String) {
        self.name = name
    }

    func addEngine(engine: Engine) {
        self.engines.append(engine)
    }
}

// create 3 factories
let f1 = Factory.init(name: "f1")
let f2 = Factory.init(name: "f2")
let f3 = Factory.init(name: "f3")
let factories = [f1,f2,f3]

let p1 = Player.init(name: "Bob")

if let firstEngine = f1.engines.first {
    firstEngine.setOwner(owner: p1)
}

print ("All factories: \(factories)")

print ("p1 = \(p1.name), engines: \(p1.engines)")

for (index, f) in factories.enumerated() {
    print ("#\(index), Owners: \(f.owners)")
}

// filter all factories NOT owned by player

let filtered = factories.map({ $0.engines.filter({ (eng: Engine) -> Bool in
        return (eng.owner != nil)
    })})

print ("factories not owned by player")

print (filtered)

输出如下:

All factories: [f1, f2, f3]
p1 = Bob, engines: [f1 - engine]
#0, Owners: Optional([Bob])
#1, Owners: Optional([])
#2, Owners: Optional([])
factories not owned by player
[[f1 - engine], [], []]

我遇到的问题是最后一个过滤器代码;

// filter all factories NOT owned by player

let filtered = factories.map({ $0.engines.filter({ (eng: Engine) -> Bool in
        return (eng.owner != nil)
    })})

这只返回引擎不是零的工厂,

我希望使用:

return (eng.owner != p1)

但是会返回错误;

error: cannot convert value of type 'Player' to expected argument type '_OptionalNilComparisonType'
        return (eng.owner != p1)

我很想知道,如何过滤工厂地图,只返回给定玩家拥有的所有工厂的列表?

非常感谢

2 个答案:

答案 0 :(得分:1)

我认为这就是你要找的东西:

extension Factory {
    func isOwned(by player: Player?) -> Bool {
        return self.engines.contains(where: { $0.isOwned(by: player)} )
    }
}

extension Engine {
    func isOwned(by player: Player?) -> Bool {
        return self.owner === player
    }
}

let factoriesNotOwnedByP1 = factories.filter { !$0.isOwned(by: p1) }

以下是我对您现有代码所做的其他一些更改:

import Foundation

class Factory {
    let name: String
    var engines = [Engine]()

    init(name: String) {
        self.name = name
        self.engines += (1...3).map{ _ in Engine(parent: self) }
    }

    var owners: [Player]? {
        return self.engines
            .lazy
            .flatMap { engine in engine.owner.map{ (engine: engine, owner: $0) } }
            .sorted { $0.owner.turnOrder < $1.owner.turnOrder }
            .map { $0.owner }
    }

    func isOwned(by player: Player?) -> Bool {
        return self.engines.contains(where: { $0.isOwned(by: player)} )
    }
}

extension Factory: CustomStringConvertible {
    var description: String { return self.name }
}





class Engine {
    weak var parent: Factory?
    weak var owner: Player?

    init(parent: Factory) {
        self.parent = parent
    }

    func setOwner(owner: Player) {
        self.owner = owner
        self.owner?.addEngine(engine: self)
    }
}

extension Engine: CustomStringConvertible {
    var description: String {
        guard let parent = self.parent else { return "N/A" }
        return ("\(parent.name) - engine")
    }
}





class Player {
    let name: String
    var engines = [Engine]()
    var turnOrder = 0

    init(name: String) {
        self.name = name
    }

    func addEngine(engine: Engine) {
        self.engines.append(engine)
    }
}

extension Player: CustomStringConvertible {
    var description: String { return self.name }
}

let factories = [
    Factory(name: "f1"),
    Factory(name: "f2"),
    Factory(name: "f3"),
]

let p1 = Player(name: "Bob")

factories.first?.engines.first?.setOwner(owner: p1)

print ("All factories: \(factories)")

print ("p1 = \(p1.name), engines: \(p1.engines)")

for (index, f) in factories.enumerated() {
    print("#\(index), Owners: \(String(describing: f.owners))")
}


let factoriesNotOwnedByP1 = factories.filter { !$0.isOwned(by: p1) }

print("factories not owned by player: ")
print(factoriesNotOwnedByP1)

答案 1 :(得分:0)

你需要告诉swift什么类型.owner是:

let filtered = factories.map({ $0.engines.filter({ (eng: Engine) -> Bool in
    return (eng.owner as? Player != p1)
})})

编辑:它可能实际上是&#39; p1&#39;需要设置为播放器,错误消息不指定。