2017-02-22 65 views
1

Очень часто мне приходилось хешировать пару значений. Часто я просто создаю диапазон между num1 и num2 и hash, который является ключом, но это довольно медленно, потому что расстояние между этими двумя числами может быть довольно большим.Использование пары значений в качестве ключа

Как можно объединить пару значений в таблицу? Например, скажем, что я выполняю итерацию через массив и хочу хэшировать каждую возможную пару значений в хеш-таблицу, где ключ - это пара чисел, а значение - их сумма. Каков эффективный способ сделать это? Я также думал о хэшировании массива как ключа, но это не работает.

Кроме того, как можно было бы расширить это до 3,4 или 5 номеров?

EDIT: Я имею в виду хеширование для поиска O (1) в хэш-таблице.

+0

Можете ли вы использовать строку '' num1: num2''? – Dbz

+0

@Dbz Я не был уверен, что это было бы эффективно: конвертировать числа в строки перед их хэшированием. Но если это наилучший способ, я обязательно буду отмечать это как правильное. – Sunny

+0

- все значения положительные? являются ли они целыми числами? – eiko

ответ

1

Просто сделай это.

Вы можете просто хэш на массиве ...

Проверка

Позвольте мне показать небольшой эксперимент:

array = [ [1,2], [3,4], ["a", "b"], ["c", 5] ] 

hash = {} 

array.each do |e| 
    e2 = e.clone 

    e << "dummy" 
    e2 << "dummy" 

    hash[e] = (hash[e] || 0) + 1 

    hash[e2] = (hash[e2] || 0) + 1 

    puts "e == e2: #{(e==e2).inspect}, e.id = #{e.object_id}, e.hash = #{e.hash}, e2.id = #{e2.object_id}, e2.hash = #{e2.hash}" 
end 

puts hash.inspect 

Как вы видите, я беру несколько массивов, клонировать их, изменять их отдельно; после этого мы уверены, что e и e2 - это разные массивы (т. е. разные идентификаторы объектов); но они содержат одни и те же элементы. После этого два разных массива используются в качестве хеш-ключей; и поскольку они имеют одинаковый контент, хэшируются вместе.

e == e2: true, e.id = 19797864, e.hash = -769884714, e2.id = 19797756, e2.hash = -769884714 
e == e2: true, e.id = 19797852, e.hash = -642596098, e2.id = 19797588, e2.hash = -642596098 
e == e2: true, e.id = 19797816, e.hash = 104945655, e2.id = 19797468, e2.hash = 104945655 
e == e2: true, e.id = 19797792, e.hash = -804444135, e2.id = 19797348, e2.hash = -804444135 
{[1, 2, "dummy"]=>2, [3, 4, "dummy"]=>2, ["a", "b", "dummy"]=>2, ["c", 5, "dummy"]=>2} 

Как вы видите, вы можете не только использовать массивы в качестве ключей, но он также признает их как «то же самое» (а не какой-то странный идентификатор объекта, который также может быть).

Caveat

Очевидно, что это работает только в одной точке. Содержимое содержимого массивов должно быть четко определено относительно хэширования. Например, вы можете использовать разумные вещи, такие как строки, числа, другие массивы, даже nil.

Ссылка

От http://ruby-doc.org/core-2.4.0/Hash.html:

Два объекты относятся к одной и той же хэш-ключа, когда их хэш-значение идентично и два объекта EQL? друг другу.

От http://ruby-doc.org/core-2.4.0/Array.html#method-i-eql-3F:

EQL (другие) → истинных или ложных

Возвращает истину, если я и другие такие же объект, или оба массива с одинаковым содержимым (? согласно объекту # eql?).

хэш → целое число

Вычислить хэш-код для этого массива.

Два массива с одинаковый контент будет иметь одинаковый хэш-код (и будет использоваться с использованием eql?).

Emphasis mine.

+0

Это похоже на тот же ответ, что и мой :) с большим количеством объяснений о том, как работает 'hash' – Dbz

1

Если вы используете range или array, то вы также можете позвонить по телефону hash и использовать его.

(num1..num2).hash [num1, num2].hash

Это возвращает ключ, который вы можете использовать в качестве хэша. Я понятия не имею, насколько это эффективно. Он показывает исходный код на range documentation и array documentation

Другой способ, который я сделал бы, - это превратить числа в строки. Это лучшее решение, если вы беспокоитесь о столкновениях с хэшем.

'num1:num2'

И рубиновые-эск способов, которые я хотел бы решить вашу проблему, являются:

number_array.combination(2).each { |arr| my_hash[arr.hash] = arr } number_array.combination(2).each { |arr| my_hash[arr.join(":")] = arr }

+0

Значения, возвращаемые 'hash', не гарантируются, чтобы быть уникальными, чтобы избежать столкновений. Они просто должны быть в основном уникальными. – tadman

+0

@tadman У вас есть источник этого? – Dbz

+2

Это * определение * хэш-функции: оно отображает большое (r) (потенциально бесконечное) пространство ввода на небольшое (er) конечное выходное пространство. Принцип Pigeonhole гарантирует, что * должно быть * столкновениями. –

0

Хэш таблица, где ключ пара Nums и значение их сумма:

h = {} 
[1,4,6,8].combination(2){|ar| h[ar] = ar.sum} 
p h #=>{[1, 4]=>5, [1, 6]=>7, [1, 8]=>9, [4, 6]=>10, [4, 8]=>12, [6, 8]=>14} 

Обратите внимание, что использование массивов в качестве хэш-ключей не проблема вообще. Чтобы увеличить это до 3,4 или 5 номеров, используйте combination(3) #or 4 or 5.