Какой подход лучше, чтобы сохранить значение или оценить каждый раз? - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь понять, какой из следующих вариантов будет лучше.

У меня есть Array из struct с

struct A {
    var selectionCount: Int
}

var ayes = [A]()

Должен ли я зацикливаться на элементах каждый раз, если я хочу знать, был ли выбран какой-либо элемент.

func selectedCount() -> Int {
    return ayes.filter({ $0.selectionCount != 0 }).reduce(0, +)
}
// OR

Сохраните var и обращайтесь к нему каждый раз, если я хочу знать, был ли сделан какой-либо выбор.

var totalSelectedElements = 0

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

func deselect(at: Int) {
    ayes[at].selectionCount -= 1
    totalSelectedElements -= 1
}

Ответы [ 4 ]

0 голосов
/ 06 сентября 2018

Важно отличать интерфейс от реализации . Сначала спроектируйте нужный интерфейс, а затем вы всегда можете изменить внутреннюю реализацию в соответствии с вашими потребностями (производительность или объем памяти).

Я считаю, что массив 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

Альтернативная реализация - тот же интерфейс

Это решение объединяет @ предложение Ракеша Шастри об использовании словаря с вашей идеей ведения счета:

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
    }
}

Это позволяет избежать необходимости в предварительно выделенном массиве, но все же обеспечивает быстрый доступ через словарь и внутренний счетчик.

0 голосов
/ 06 сентября 2018

На мой взгляд, есть даже лучший подход.

Поскольку у вас уже есть информация в массиве - всякий раз, когда сделан выбор, сохраняет индекс выбранного элемента в другом массиве.

  • Если вы хотите узнать, был ли выбран конкретный элемент, вы можете просто проверить, находится ли индекс этого элемента в массиве.

  • Если вы хотите узнать общее количество выбранных элементов, просто получите счетчик массива.

Улучшенное решение на основе комментариев:

В конце концов, еще лучшим решением будет сохранение счетчика выбранного индекса в словаре, где ключ будет индекс и счет будет значение .

  • Если вы хотите проверить, выбран ли конкретный элемент, вы можете проверить, возвращает ли индекс значение при передаче в качестве ключа к словарю.

  • Если вы хотите подсчитать количество уникальных выборок, получите подсчет количества ключей в словаре.

  • Если вы хотите подсчитать количество выборок, получите сумму значений в словаре.

Примечание: вам нужно будет удалить ключ из словаря, когда выбранный счет достигнет 0.

0 голосов
/ 06 сентября 2018

Если под «лучшим подходом» подразумевается производительность, то наличие значения наготове, конечно, намного быстрее, чем прохождение сотен, если не тысяч элементов, и получение их свойств, а затем их сложение.

Если «лучший подход» означает лучший дизайн API, то первый вариант более универсален, поскольку из вашего кода любой объект, вызов select(at:) или deselect(at:) и т. Д. selectionCount может стать отрицательным ... И ваш код будет с состоянием, это будет зависеть от состояния переменной.

0 голосов
/ 06 сентября 2018

Я склонен голосовать против хранения информации, которая может быть получена из уже существующих данных. Этот подход, однако, может иметь решающее значение для производительности. Итак, возникают два вопроса:

  1. Каков порядок величины в вашем массиве? Мы говорим только о нескольких сотнях предметов? Если это так, вы сможете спокойно игнорировать добавленные накладные расходы.
  2. Как часто будет необходимо получить доступ к рассматриваемому значению?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...