Is there a quick and easy way to create a checksum from basic Ruby data structures?

I have a data structure ( Hash ) that looks something like this:

 { foo: "Test string", bar: [475934759, 5619827847] } 

I am trying to create a checksum from this Hash to check for equality in the future. I tried to use the Hash method for Hash , which led to a satisfactorily pleasant hash, but it turned out that the same Hash would produce a different hash after restarting the interpreter.

I just want to create a 128 bit checksum from an instance of Hash , String or Array .

Is it possible?

+6
source share
3 answers

You can calculate your own hash based on a marshal or JSON dump object.

This computes the marshal dump MD5 hash:

 require 'digest/md5' hash = { foo: "Test string", bar: [475934759, 5619827847] } Marshal::dump(hash) #=> "\x04\b{\a:\bfooI\"\x10Test string\x06:\x06ET:\bbar[\ai\x04'0^\x1Cl+\b\x87\xC4\xF7N\x01\x00" Digest::MD5.hexdigest(Marshal::dump(hash)) #=> "1b6308abdd8f5f6290e2825a078a1a02" 

Update

You can implement your own strategy, although I would not recommend changing the main functions:

 class Hash def _dump(depth) # this doesn't cause a recursion because sort returns an array Marshal::dump(self.sort, depth) end def self._load(marshaled_hash) Hash[Marshal::load(marshaled_hash)] end end Marshal::dump({foo:1, bar:2}) #=> "\x04\bu:\tHash\e\x04\b[\a[\a:\bbari\a[\a:\bfooi\x06" Marshal::dump({bar:2, foo:1}) #=> "\x04\bu:\tHash\e\x04\b[\a[\a:\bbari\a[\a:\bfooi\x06" Marshal::load(Marshal::dump({foo:1, bar:2})) #=> {:bar=>2, :foo=>1} 
+6
source

To build on @Stefan the answer above, if the hash order is important, sort the result before pushing it through Mashall.

 require 'digest/md5' hash = { 'foo'=> "Test string", 'bar'=> [475934759, 5619827847] } puts Digest::MD5.hexdigest(Marshal::dump(hash.collect{|k,v| [k,v]}.sort{|a,b| a[0] <=> b[0]})) # 8509c564c0ae8dcb6c2b9b564ba6a03f hash = { 'bar'=> [475934759, 5619827847], 'foo'=> "Test string" } puts Digest::MD5.hexdigest(Marshal::dump(hash.collect{|k,v| [k,v]}.sort{|a,b| a[0] <=> b[0]})) # 8509c564c0ae8dcb6c2b9b564ba6a03f 
+2
source

If you need to generate a checksum for the contents of the hash, regardless of the order of the data, using marshal or sorting or other methods will not work.

The only solid way I've found so far is this:

 require 'digest/md5' hash1 = { "a" => 1, "b" => "2", c: { d: "3" } } hash2 = { c: { d: "3" }, "a" => 1, "b" => "2" } Digest::MD5.hexdigest(Marshal.dump(hash1)) # => "5def3b2cbdddd3aa6730b6d0527c2d79" Digest::MD5.hexdigest(Marshal.dump(hash2)) # => "8155698ccfb05b8db01490e9b9634fd9" Digest::MD5.hexdigest(hash1.to_s.chars.sort.join) # => "812bb65d65380fc1e620a9596806cc35" Digest::MD5.hexdigest(hash2.to_s.chars.sort.join) # => "812bb65d65380fc1e620a9596806cc35" 
0
source

Source: https://habr.com/ru/post/955978/


All Articles