#go #hashmap
#Вперед #hashmap
Вопрос:
У меня есть карта с целочисленными значениями. Я хочу обновить значение, а затем проверить, превышает ли обновленное значение пороговое значение.
Если бы мне не нужно было проверять новое значение, я бы просто сделал
map[key] = 1
Очевидным изменением, если я захочу проверить новое значение, будет:
old_val := map[key]
new_val := old_val 1
map[key] = new_val
if (new_val > threshold) {
return
}
Однако при этом выполняется два индексных вызова карты, что не обязательно является операцией с постоянным временем.
Что я хотел бы сделать, это что-то вроде:
val_p := amp;(map[key])
*(val_p) = 1
if (*(val_p) > threshold) {
return
}
Однако карты GoLang не являются адресуемыми по дизайну, потому что адреса, очевидно, могут меняться (хотя в данном случае это не изменилось бы, потому что я не изменяю карту).
Есть ли какая-нибудь функция, которую я мог бы использовать для обновления элемента на карте, которая возвращает новое значение? Специально для целых чисел?
Комментарии:
1. Нет, не существует. Вы измерили проблему с производительностью и составили профиль, чтобы сузить ее до стоимости второго поиска по карте, или это чисто умозрительная оптимизация?
2. Нет, это просто предположение, и я сомневаюсь, что это существенно повлияет на производительность. Немного раздражает, что это то, чему препятствует дизайн, который оказывает ощутимое (хотя, вероятно, небольшое) влияние на производительность.
3. Хорошо, что такие волшебные / перегруженные вещи предотвращены дизайном, IMO. Это делает код намного понятнее для чтения.
4. Если вы не измерили и не профилировали проблему производительности, вы не можете утверждать, что это оказывает ощутимое влияние. Вы предполагаете, что это возможно. Попытки исправить проблему, о существовании которой вы не знаете, обычно контрпродуктивны.
5. Было бы неплохо, если бы существовал способ передать функцию на карту вместе с ключом, а затем обновить ее и вернуть связанное значение. Это определенно то, что должно быть возможно.
Ответ №1:
Вы не можете сделать это с «простыми» значениями по причинам, которые вы упомянули в вопросе.
Что вы можете сделать, так это сохранить оболочку или указатель на карте, и поэтому вам нужно только выполнить поиск значения, и вам нужно сделать это только один раз; изменение данных изменяет указанное значение, которое находится за пределами карты, поэтому вам не нужно переназначать (указатель не меняется).
Например:
const threshold = 3
m := map[string]*int{
"one": new(int),
}
for {
p := m["one"]
fmt.Println("data=", *p)
*p
if *p > threshold {
fmt.Println("threshold reached", *p)
break
}
}
Это выводит (попробуйте это на игровой площадке Go):
data= 0
data= 1
data= 2
data= 3
threshold reached 4
Хотя обратите внимание, что это может быть не быстрее из-за косвенных указателей. Измерьте, является ли это важной частью вашего приложения.
Комментарии:
1. И сборщику мусора (GC) придется следовать всем этим указателям.