Насколько дорогой является "ключевая" функция хэша Ruby?
Я использую пару хешей, где значения одних хешей являются ключом других.
Мне нужно использовать key
пару раз, чтобы получить ключ для значения, чтобы я мог использовать его для доступа к чему-либо в другом хеше.
Мне было интересно, какое влияние на производительность это может оказать. В моей ситуации этих хэшей немного, а их содержимое мало, но я хочу знать теоретически.
Должен ли я избегать использования этого слишком много? Как это работает по сравнению с получением значения для ключа?
2 ответа
Думайте об этом так: вы иногда делаете дополнительный шаг, чтобы получить ценность. Вот что происходит каждый раз, когда вы используете условный тест и добавляете пару шагов к вычислению.
Очевидно, что это связано с небольшими накладными расходами, но на данный момент беспокоиться об этом преждевременно. Вы МОЖЕТЕ почувствовать разницу, используя класс Benchmark, чтобы проверить свой альтернативный способ получения хеш-ключа по сравнению с обычным способом.
Я подозреваю, что вам придется сделать несколько миллионов циклов, чтобы увидеть заметную разницу.
Вот как я создаю обратное отображение, упомянутое @fontanus:
hash = {a:1, b:2}
hash.merge!(Hash[hash.values.zip(hash.keys)])
Что приводит к:
{
:a => 1,
:b => 2,
1 => :a,
2 => :b
}
Это также может быть сделано путем преобразования хеша в массив, сглаживания его и обращения к нему, а затем превращения его обратно в хеш, но я считаю, что это менее интуитивно понятно, чем выше. YMMV.
hash.merge!(Hash[*hash.to_a.flatten.reverse])
@steenslag напомнил мне о Hash.invert
, Я знал, что что-то есть, но не мог вспомнить название метода:
>> hash.merge! (hash.invert) {: a => 1,: b => 2, 1 =>: а, 2 =>:b }
Подайте ему голос за это!
Поиск в ruby 1.9.3 и 2.0.0 - O(n) операции.
static VALUE
rb_hash_key(VALUE hash, VALUE value)
{
VALUE args[2];
args[0] = value;
args[1] = Qnil;
rb_hash_foreach(hash, key_i, (VALUE)args);
return args[1];
}
Реализация rb_hash_foreach
:
void
rb_hash_foreach(VALUE hash, int (*func)(ANYARGS), VALUE farg)
{
struct hash_foreach_arg arg;
if (!RHASH(hash)->ntbl)
return;
RHASH_ITER_LEV(hash)++;
arg.hash = hash;
arg.func = (rb_foreach_func *)func;
arg.arg = farg;
rb_ensure(hash_foreach_call, (VALUE)&arg, hash_foreach_ensure, hash);
}
Тем не менее, ваши хэши маленькие. @theTinMan правильно относится к преждевременной оптимизации, и вам не следует об этом беспокоиться.