Ruby 将深度嵌套哈希展平到数组以进行sha1哈希
我想从ruby散列计算一个唯一的sha1散列。我想到Ruby 将深度嵌套哈希展平到数组以进行sha1哈希,ruby,hash,sha1,sha,Ruby,Hash,Sha1,Sha,我想从ruby散列计算一个唯一的sha1散列。我想到 (深度)将散列转换为数组 排序数组 通过空字符串联接数组 计算sha1 考虑以下散列: hash = { foo: "test", bar: [1,2,3] hello: { world: "world", arrays: [ {foo: "bar"} ] } } 如何将这种嵌套哈希放入一个数组中,如 [:foo, "test", :bar, 1, 2, 3, :hello, :wor
- (深度)将散列转换为数组
- 排序数组
- 通过空字符串联接数组
- 计算sha1
hash = {
foo: "test",
bar: [1,2,3]
hello: {
world: "world",
arrays: [
{foo: "bar"}
]
}
}
如何将这种嵌套哈希放入一个数组中,如
[:foo, "test", :bar, 1, 2, 3, :hello, :world, "earth", :arrays, :my, "example"]
然后我会对数组进行排序,用array.join(“”
连接它,然后像这样计算sha1散列:
require 'digest/sha1'
Digest::SHA1.hexdigest hash_string
a = {a: "a", b: "b"}
b = {a: "b", b: "a"}
在展平散列并对其排序时,这两个散列产生相同的输出,即使a==b=>false
编辑2
整个过程的用例是产品数据比较。产品数据存储在散列中,然后序列化并发送到创建/更新产品数据的服务
我想检查产品数据内部是否有任何更改,因此我从产品内容生成一个哈希,并将其存储在数据库中。下次加载同一个产品时,我会再次计算哈希值,将其与数据库中的哈希值进行比较,并确定该产品是否需要更新。编辑:正如您所述,两个具有不同顺序键的哈希值应给出相同的字符串。我将重新打开哈希类以添加新的自定义展平方法:
class Hash
def custom_flatten()
self.sort.map{|pair| ["key: #{pair[0]}", pair[1]]}.flatten.map{ |elem| elem.is_a?(Hash) ? elem.custom_flatten : elem }.flatten
end
end
说明:
将哈希转换为已排序的对数组(用于比较具有不同键顺序的哈希)sort
是一种将键与最终展平数组中的值区分开来的技巧,以避免.map{124; pair}[“key:{pair[0]}”,pair[1]}
{a:{b:{c::d}}的问题。自定义展平=={a::b,c::d}。自定义展平
将数组转换为单个值数组展平
在任何剩余子散列上回调map{elem | elem.is_a?(散列)?elem.custom_flatten:elem}
fully_flatte
require 'digest/sha1'
Digest::SHA1.hexdigest hash.custom_flatten.to_s
编辑:正如您所详述的,两个键顺序不同的散列应该给出相同的字符串。我将重新打开哈希类以添加新的自定义展平方法:
class Hash
def custom_flatten()
self.sort.map{|pair| ["key: #{pair[0]}", pair[1]]}.flatten.map{ |elem| elem.is_a?(Hash) ? elem.custom_flatten : elem }.flatten
end
end
说明:
将哈希转换为已排序的对数组(用于比较具有不同键顺序的哈希)sort
是一种将键与最终展平数组中的值区分开来的技巧,以避免.map{124; pair}[“key:{pair[0]}”,pair[1]}
{a:{b:{c::d}}的问题。自定义展平=={a::b,c::d}。自定义展平
将数组转换为单个值数组展平
在任何剩余子散列上回调map{elem | elem.is_a?(散列)?elem.custom_flatten:elem}
fully_flatte
require 'digest/sha1'
Digest::SHA1.hexdigest hash.custom_flatten.to_s
我不知道有什么宝石能像你要找的那样。ruby中有一个方法,但它不会递归地展平嵌套哈希。下面是一个直接的递归函数,它将按照您在问题中要求的方式展开:
def completely_flatten(hsh)
hsh.flatten(-1).map{|el| el.is_a?(Hash) ? completely_flatten(el) : el}.flatten
end
这将产生
hash = {
foo: "test",
bar: [1,2,3]
hello: {
world: "earth",
arrays: [
{my: "example"}
]
}
}
completely_flatten(hash)
#=> [:foo, "test", :bar, 1, 2, 3, :hello, :world, "earth", :arrays, :my, "example"]
要获取要查找的字符串表示形式(在进行sha1哈希之前),请在排序之前将数组中的所有内容转换为字符串,以便对所有元素进行有意义的比较,否则将出现错误:
hash_string = completely_flatten(hash).map(&:to_s).sort.join
#=> "123arraysbarearthexamplefoohellomytestworld"
我不知道有什么宝石能像你要找的那样。ruby中有一个方法,但它不会递归地展平嵌套哈希。下面是一个直接的递归函数,它将按照您在问题中要求的方式展开:
def completely_flatten(hsh)
hsh.flatten(-1).map{|el| el.is_a?(Hash) ? completely_flatten(el) : el}.flatten
end
这将产生
hash = {
foo: "test",
bar: [1,2,3]
hello: {
world: "earth",
arrays: [
{my: "example"}
]
}
}
completely_flatten(hash)
#=> [:foo, "test", :bar, 1, 2, 3, :hello, :world, "earth", :arrays, :my, "example"]
要获取要查找的字符串表示形式(在进行sha1哈希之前),请在排序之前将数组中的所有内容转换为字符串,以便对所有元素进行有意义的比较,否则将出现错误:
hash_string = completely_flatten(hash).map(&:to_s).sort.join
#=> "123arraysbarearthexamplefoohellomytestworld"
使用封送处理进行快速序列化
在散列之前,您还没有阐明更改数据结构的有用理由。因此,除非数据结构包含不支持的对象(如绑定或PROS),否则应考虑速度。例如,使用已更正语法的哈希变量:
require 'digest/sha1'
hash = {
foo: "test",
bar: [1,2,3],
hello: {
world: "world",
arrays: [
{foo: "bar"}
]
}
}
Digest::SHA1.hexdigest Marshal.dump(hash)
#=> "f50bc3ceb514ae074a5ab9672ae5081251ae00ca"
封送处理通常比其他序列化选项更快。如果你只需要速度,那将是你最好的选择。然而,由于其他原因,您可能会发现JSON、YAML或简单的“to#s”或“inspect”更能满足您的需求。只要比较对象的类似表示,哈希对象的内部格式与确保对象唯一或未修改基本无关。使用封送处理进行快速序列化
在散列之前,您还没有阐明更改数据结构的有用理由。因此,除非数据结构包含不支持的对象(如绑定或PROS),否则应考虑速度。例如,使用已更正语法的哈希变量:
require 'digest/sha1'
hash = {
foo: "test",
bar: [1,2,3],
hello: {
world: "world",
arrays: [
{foo: "bar"}
]
}
}
Digest::SHA1.hexdigest Marshal.dump(hash)
#=> "f50bc3ceb514ae074a5ab9672ae5081251ae00ca"
封送处理通常比其他序列化选项更快。如果你只需要速度,那将是你最好的选择。然而,由于其他原因,您可能会发现JSON、YAML或简单的“to#s”或“inspect”更能满足您的需求。只要比较对象的类似表示形式,哈希对象的内部格式与确保对象唯一或未修改基本无关。任何基于展平哈希的解决方案都会因嵌套哈希而失败。一个健壮的解决方案是显式地递归排序每个散列的键(从ruby 1.9.x开始,保留散列键顺序),然后将其序列化为字符串并对其进行摘要
def canonize_hash(h)
r = h.map { |k, v| [k, v.is_a?(Hash) ? canonize_hash(v) : v] }
Hash[r.sort]
end
def digest_hash(hash)
Digest::SHA1.hexdigest canonize_hash(hash).to_s
end
digest_hash({ foo: "foo", bar: "bar" })
# => "ea1154f35b34c518fda993e8bb0fe4dbb54ae74a"
digest_hash({ bar: "bar", foo: "foo" })
# => "ea1154f35b34c518fda993e8bb0fe4dbb54ae74a"
任何基于展平散列w的解决方案