如何为具有特定内容的哈希生成唯一标识符?

时间:2014-12-23 17:11:56

标签: ruby hash

对于缓存层,我需要为哈希创建一个唯一的sha。它对于该哈希的内容应该是唯一的。具有相同配置的两个哈希应具有相同的sha。

in_2014 = { scopes: [1, 2, 3], year: 2014 }
not_in_2104 = { scopes: [1, 2, 3], year: 2015 }
also_in_2014 = { year: 2014, scopes: [1, 2, 3] }

in_2014 == also_in_2014 #=> true
not_in_2104 == in_2014  #=> false

现在,为了存储它并快速查看,需要转动它 进入一个shasum的东西。简单地转换为字符串不起作用, 所以从中生成hexdigest也不起作用:

require 'digest'
in_2014.to_s == also_in_2014.to_s #=> false
Digest::SHA2.hexdigest(in_2014.to_s) == Digest::SHA2.hexdigest(also_in_2014.to_s) #=> false

我想要的是一个shasum或其他一些标识符,可以让我这样做 比较哈希与彼此。我希望像最后一个测试一样,如果哈希的内容匹配,它将返回true。

我可以在to_s之前对哈希进行排序,但这对我来说似乎很狡猾。一世 我是一个人,害怕我在那里忽略了一些事情(一个sort返回一个数组,不再是一个哈希值)。在那儿 我忽略了一些简单的东西?或者这根本不可能?

FWIW,我们在下面的场景中需要这个:

Analysis.find_by_config({scopes: [1,2], year: 2014}).datasets
Analysis.find_by_config({account_id: 1337}).datasets

class Analysis < ActiveRecord::Base
  def self.find_by_config(config)
    self.find_by(config_digest: shasum_of(config))
  end

  def self.shasum_of(config)
     #WAT?
  end

  def before_saving
    self.config_digest = Analysis.shasum_of(config)
  end
end

请注意,此处,Analysis 具有列“范围”或“年”或 “帐户ID”。这些是任意配置,我们只需要查看 数据集。

2 个答案:

答案 0 :(得分:4)

我不推荐使用hash方法,因为它不可靠。您可以通过在IRB中执行{one: 1}.hash,在Rails控制台中执行相同的命令,然后在另一台机器上的IRB和/或Rails控制台中快速确认这一点。输出会有所不同。

坚持Digest::SHA2.hexdigest(string)会更明智。

您必须对哈希进行排序并将其字符串化。这就是我要做的事情:

hash.sort.to_s

如果您不想要数组,无论出于何种原因,请将其转回哈希值。

Hash[hash.sort].to_s #=> will return hash

而且,无论出于何种原因,如果您不想将哈希值转换为数组然后返回哈希值,请执行以下操作以获取哈希值到哈希值:

def prepare_for_sum( hash )
  hash.keys.sort.each_with_object({}) do |key, return_hash|
    return_hash[key] = hash[key]
  end.to_s
end

在上述方法中使用一些修改,您也可以对值进行排序;它可以在Array或Hash值的情况下提供帮助。

答案 1 :(得分:0)

事实证明,Ruby有一个针对这种情况的方法:Hash.hash

in_2014.hash == also_in_2014.hash