查找数组元素索引的更好方法?

时间:2019-03-15 06:47:19

标签: arrays swift indexing architecture grid

我一般对Swift和编程都不熟悉。

我正在处理一个带有二维数组的项目,以表示在其中存储自定义对象的网格:

class Grid {
    var element: [[GridElement]]
}

我经常需要通过其坐标访问元素。例如:

let gridElement = grid.element[coord.x][coord.y]

但是,我还需要经常从给定的gridElement(其在2d数组中的索引)获取坐标。这导致嵌套循环似乎不是最快或最优雅的解决方案:

func getCoord(_ gridElement: GridElement) -> Coord {
    for x in 0..<xSize {
        for y in 0..<ySize {
            if element[x][y] == gridElement { return Coord(x: x, y: y) }
        }
    }
    return Coord(x: -1, y: -1)
}

由于我希望它在大型网格上能够正常工作,所以这看起来不是解决方案。我想念一些简单的东西吗?

我正在考虑将坐标存储在GridElement对象本身中,但这也感觉很糟糕,因为当GridElement更改位置时,我需要不断更新它。

这不仅仅是设计/体系结构问题,而不是寻找神奇的功能来解决我的问题。感觉应该建立双向参考的设计模式,但我还没有找到答案。有什么建议吗?

3 个答案:

答案 0 :(得分:0)

  

我正在考虑将坐标存储在GridElement对象本身中,但是这也感觉很糟糕,因为当GridElement更改位置时,我需要不断更新它。

我认为类似的解决方案是可行的。您可以将坐标存储在另一个字典中,而不是将其存储在网格元素对象中:

private var gridElementPositionDict: [GridElement: Coord]

正如您所说,这将要求您在网格元素更改位置时不断设置gridElementPositionDict的值。 但是,您可以使用一些封装,以便仅将它们设置在一个位置。

首先,创建elements数组private,然后向subscript类添加一个带有两个参数的Grid。下标将接受Coord,用于访问特定位置的特定网格元素。在此下标的设置者中,您可以修改gridElementPositionDict以设置GridElement的新位置。

然后,您可以编写另一个方法(或下标),该方法接受返回其位置的GridPosition

您还可以添加诸如swapElements(at:and:)changeElementPositon(_:to:)之类的方法。所有这些都与封装数据结构有关。

这里有一些代码作为示例:

class Grid<T: Hashable> {
    private var elements: [[T?]]
    private var elementsPositionDict: [T: Coord]

    init() {
        elements = [
            [nil, nil, nil, nil],
            [nil, nil, nil, nil],
            [nil, nil, nil, nil],
            [nil, nil, nil, nil],
        ]
        elementsPositionDict = [:]
    }

    subscript(_ coord: Coord) -> T? {
        get { return elements[coord.x][coord.y] }
        set {
            // this is the ONLY place you modify the dictionary
            if let oldValue = elements[coord.x][coord.y] {
                elementsPositionDict[oldValue] = nil
            }
            elements[coord.x][coord.y] = newValue
            if let v = newValue {
                elementsPositionDict[v] = coord
            }
        }
    }

    func coord(of element: T) -> Coord? {
        return elementsPositionDict[element]
    }
}

答案 1 :(得分:0)

我认为您的getCoord函数应类似于:

func getCoord(_ gridElement: GridElement) -> Coord {
    for (i, row) in element.enumerated() {
        if let index = row.firstIndex(of: gridElement) {
            return Coord(x: i, y: index)
        }
    }
    return Coord(x: -1, y: -1)
}

答案 2 :(得分:-1)

由于您拥有Coord类/结构,为什么不将元素存储为CoordGridElement的字典,而是避免使用2D数组以及Coord与索引中的索引之间的映射数组。这是我的建议,如何实现Grid

class Grid {
    private var elements: [Coord: GridElement]

    init() {
        elements = [:]
    }

    func element(at coord: Coord) -> GridElement? {
       return elements[coord]
    }

    func coord(for gridElement: GridElement) -> Coord? {
        return elements.first { item in item.value == gridElement }?.key
    }
}

请注意,Coord必须实现Hashable,并且我将字典设为私有,因为我认为如果通过函数访问字典,这是一个更好的设计