Насколько дорогой является "ключевая" функция хэша 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 правильно относится к преждевременной оптимизации, и вам не следует об этом беспокоиться.

Другие вопросы по тегам