每次保存值或评估哪种方法更好?

时间:2018-09-06 10:42:36

标签: arrays swift optimization higher-order-functions

我试图了解以下哪种方法更好。

我有Array的{​​{1}}

struct

如果我想知道是否已选择任何元素,是否应该每次都遍历项目。

struct A {
    var selectionCount: Int
}

var ayes = [A]()

存储一个func selectedCount() -> Int { return ayes.filter({ $0.selectionCount != 0 }).reduce(0, +) } // OR 并在每次我想知道是否进行选择时都进行访问。

var

4 个答案:

答案 0 :(得分:2)

区分接口实现非常重要。首先设计所需的接口,然后可以随时更改内部实现以适应您的(性能与存储)需求。

我认为A的数组应该受到保护,您应该只允许通过select(at:)deselect(at:)方法进行访问。这使您可以通过以下两种方式执行内部实现:

struct Ayes {
    private struct A {
        var selectionCount = 0
    }

    private var ayes = [A](repeating: A(), count: 100)
    private var totalSelectedElements = 0

    mutating func select(at: Int) {
        ayes[at].selectionCount += 1
        totalSelectedElements += 1
    }

    mutating func deselect(at: Int) {
        guard ayes[at].selectionCount > 0 else { return }
        ayes[at].selectionCount -= 1
        totalSelectedElements -= 1
    }

    func selectCount(at: Int) -> Int {
        return ayes[at].selectionCount
    }

    var totalElements: Int {
        return totalSelectedElements
    }
}

这实际上取决于您要存储totalElements还是计算它的访问频率。通过隐藏实现细节,您可以自由更改实现,而不会影响程序的其余部分。

我喜欢维护计数以便快速访问的想法,并且通过保护对内部实现的访问,您可以保证计数是准确的。


示例:

var ayes = Ayes()

print(ayes.totalElements) // 0
ayes.select(at: 3)
ayes.select(at: 3)
ayes.select(at: 4)
print(ayes.totalElements) // 3
print(ayes.selectCount(at: 3)) // 2
ayes.deselect(at: 3)
print(ayes.selectCount(at: 3)) // 1
ayes.deselect(at: 3)
print(ayes.selectCount(at: 3)) // 0
ayes.deselect(at: 3)
print(ayes.selectCount(at: 3)) // 0
print(ayes.totalElements) // 1

替代实施-相同的界面

此解决方案结合了使用字典的@RakeshaShastri's suggestion和保持计数的想法:

struct Ayes {
    private var ayes = [Int : Int]()
    private var totalSelectedElements = 0

    mutating func select(at: Int) {
        ayes[at, default: 0] += 1
        totalSelectedElements += 1
    }

    mutating func deselect(at: Int) {
        guard var count = ayes[at] else { return }
        count -= 1
        totalSelectedElements -= 1
        ayes[at] = count == 0 ? nil : count
    }

    func selectCount(at: Int) -> Int {
        return ayes[at, default: 0]
    }

    var totalElements: Int {
        return totalSelectedElements
    }
}

这避免了对预分配数组的需求,但仍可以通过字典和内部计数快速访问。

答案 1 :(得分:1)

我认为有一种甚至更好的方法。

由于您已经在数组中存储了信息-进行选择后,将所选元素的索引存储在另一个数组中。

  • 如果您想知道是否已选择特定元素,则只需检查该元素的索引是否在数组中即可。

  • 如果您想知道所选项目的总数,只需获取数组的数量即可。

基于评论的改进解决方案:

最后,一个更好的解决方案是将所选索引的计数存储在字典中,其中将是 index ,而 count < / strong>为

  • 如果要检查是否选择了特定元素,则可以检查将索引作为键传递给字典时索引是否返回值。

  • 如果要计算唯一选择项的数量,请获取字典中键的数量。

  • 如果要计算选择数量,请获取字典中值的总和。

注意:当所选计数达到0时,您需要从字典中删除键。

答案 2 :(得分:0)

我倾向于反对存储可以从现有数据中得出的信息。但是,这种方法可能对性能至关重要。因此出现了两个问题:

  1. 阵列中的数量级是多少?我们只说几百个项目吗?如果是这样,您应该可以安全地忽略增加的开销。
  2. 需要多长时间访问一次所讨论的值?

答案 3 :(得分:0)

如果性能是“更好的方法”的含义,那么拥有现成的价值当然比遍历数百个(如果不是数千个)元素并获取其属性然后将它们加起来要快得多。

如果“更好的方法”意味着更好的API设计,则前者的用途更加广泛,因为从您的代码中,任何对象调用select(at:)deselect(at:)都会使selectionCount变为否定。 。并且您的代码将是有状态的,它将依赖于变量的状态。