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

Ruby 如何为具有特定内容的哈希生成唯一标识符?,ruby,hash,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_210

对于缓存层,我需要为哈希创建一个唯一的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
现在,为了存储它并快速查找它,需要打开它 变成一个沙姆人。简单地转换为字符串不起作用, 因此,从中生成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

我以前可以对散列进行排序,但这对我来说似乎很笨拙。我 例如,我担心我忽略了一些东西,排序返回一个数组,不再是散列。有 我忽略了一些简单的事情?还是根本不可能

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
请注意,这里的分析没有列范围或年份或年份 帐户id。这些是任意配置,我们只需要查找
查看数据集。

结果表明,Ruby有一种方法可以解决这种情况:


事实证明,Ruby有一个方法可以解决这种情况:

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

坚持使用Digest::SHA2.hexdigeststring会更明智

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

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
使用上述方法中的一些修改,您也可以对值进行排序;在数组或哈希值的情况下,它会很有帮助。

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

坚持使用Digest::SHA2.hexdigeststring会更明智

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

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

使用上述方法中的一些修改,您也可以对值进行排序;在数组或散列值的情况下,它会很有帮助。

如果它是缓存,那么偶尔出现重复条目是否真的很重要?在某些情况下,重复条目会很重要。缓存就在那里,因为生成数据集实际上就像每次配置十分钟的计算时间一样昂贵。因此,我们希望存储配置,让后台工作人员计算数据集,然后从那时起,立即为某个配置提供数据集。如果是缓存,是否偶尔有重复条目真的很重要?在某些情况下,重复条目会很重要。缓存就在那里,因为生成数据集实际上就像每次配置十分钟的计算时间一样昂贵。因此,我们希望存储配置,让后台工作人员计算数据集,然后立即为某个配置提供数据集。哈希有其缺点。看看我的答案。@Humza是对的,这对于缓存来说是一个糟糕的想法,散列值在进程之间不会是常数。散列有它的缺点。请查看我的答案。@Humza是对的,这对于缓存来说是一个糟糕的想法,散列值在进程之间不会是常数。散列[hash.sort]。to_s抛出错误,无法将数组转换为散列。@berkes,对于我在响应中提供的散列效果很好。我们正在调查,因为我们的代码库得到了不同的结果。当我有更多详细信息时,将发回。哈希[Hash.sort]。to_s抛出错误,无法将数组转换为哈希。@berkes,对于我在响应中提供的哈希很好。我们正在调查,因为我们的代码库得到了不同的结果。当我有更多细节时,我会发回。