【问题标题】:What is the shortest code to get surrounding coordinates?获取周围坐标的最短代码是什么?
【发布时间】:2017-05-25 12:39:58
【问题描述】:

我不喜欢我对surroundingPositions 的以下实现来获取围绕特定位置的 x 和 y 坐标,因为在我看来,它对于简单的意图来说太长了,而且它有一个厄运金字塔结构。

struct Position: CustomStringConvertible {

    let x, y: Int

    var surroundingPositions: [Position] {
        var surroundingPositions: [Position] = []
        for x in (self.x - 1)...(self.x + 1) {
            for y in (self.y - 1)...(self.y + 1) {
                if !(x == self.x && y == self.y) {
                    surroundingPositions.append(Position(x: x, y: y))
                }
            }
        }
        return surroundingPositions
    }

    var description: String {
        return "(\(x),\(y))"
    }

}

用法:

let testPosition = Position(x: 1, y: 1)
print(testPosition.surroundingPositions)
// Output: [(0,0), (0,1), (0,2), (1,0), (1,2), (2,0), (2,1), (2,2)]

实现相同(正确)结果的最短方法是什么?我在想mapfilterreduce等函数,但目前还没有找到合适的组合...

【问题讨论】:

    标签: swift swift3


    【解决方案1】:

    好吧,您总是可以对其进行硬编码。在这里,我对增量进行了硬编码,并为每个增量创建了一个新的 Position

    var surroundingPositionsHardcoded: [Position] {
        let deltas: [(Int, Int)] = [(-1, -1), (-1, 0), (-1, +1), (0, -1), (0, +1), (+1, -1), (+1, 0), (+1, +1)]
        return deltas.map { Position(x: x+$0.0, y: y+$0.1) }
    }
    

    或者,您可以使用map 计算增量。这还有一个额外的好处,就是您可以增加周围的距离。

    var surroundingPositionsComputed: [Position] {
        let deltas = (-1...1).map { dx in (-1...1).map { dy in (dx, dy) } }
            .joined()
            .filter { $0.0 != 0 || $0.1 != 0 }
        return deltas.map { Position(x: x+$0.0, y: y+$0.1) }
    }
    

    【讨论】:

    • 特别是第二个解决方案是我正在寻找的。简短而优雅,谢谢!
    • 我应该指出(对于未来可能的读者),如果邻域“半径”是一个常数(在本例中为:1),则不应首选第二种方法。可能编译器会将deltas 计算优化为单个调用,但我建议将filter 调用放在deltas 实例化而不是return 调用上,因为(给定一个常量“半径”)对于给定位置实例的对周围位置的计算的每次调用,我们真的不想执行常量与常量的过滤。对于不同的半径,请选择 #2!
    • 我赞同@dfri 所说的。实际上,我在创建增量时使用了过滤器,但将其放在第二行以缩短行数。我更新了应用 dfri 建议的帖子并添加了一些换行符。如果距离是(并且将是)一个常数,您当然可以继续并将其设为静态变量,就像 dfri 的答案一样。
    【解决方案2】:

    由于您只查找相邻位置并且似乎对 xy 没有限制,因此您可以保存一组 (x, y) 翻译,每个翻译将给定的 Position 映射到其 8 个不同的相邻位置之一那些。

    struct Position: CustomStringConvertible {
        let x, y: Int
    
        // order of resulting neighbouring positions, given a position P
        // (1)  (2)  (3)
        // (4)  (P)  (5)
        // (6)  (7)  (8)
        private static let surroundingPositionsTranslations: [(x: Int, y: Int)] = [
            (-1, -1), (0, -1), (1, -1),
            (-1,  0),          (1,  0),
            (-1, -1), (0, -1), (1, -1)]
    
        var surroundingPositions: [Position] {
            return Position.surroundingPositionsTranslations
                .map { Position(x: x + $0.x, y: y + $0.y) }
        }
    
        var description: String {
            return "(\(x),\(y))"
        }
    }
    
    // Note that I've changed the order w.r.t. OP:s original code
    // (modify the transfotmation above to modify the order)
    let testPosition = Position(x: 1, y: 1)
    print(testPosition.surroundingPositions)
    // Output: [(0,0), (1,0), (2,0), (0,1), (2,1), (0,0), (1,0), (2,0)]
    

    【讨论】:

    • 这绝对是比我目前拥有的更好的解决方案。但是,我接受了另一个具有相同内容(硬编码)以及更灵活和优雅的解决方案(计算)的答案。不过还是谢谢你的回答!
    • @BennoKress 很乐意为您提供帮助。是的,我注意到我们同时发布了一些相同的内容:) 只要确保更喜欢“硬编码”的内容,以防您没有不同的邻域半径(如您的示例:静态并设置为 @987654326 @),作为“计算”方法,对于恒定半径,在每次调用时将不必要地执行嵌套的map、数组初始化等(可能由编译器优化),然后是不必要的filter,只是为了过滤如果使用一组静态“硬编码”转换,我们可能已经忽略了单个 self 坐标。
    猜你喜欢
    • 1970-01-01
    • 2015-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    相关资源
    最近更新 更多