Creating an Md5 Hash of a Number, String, Array, or Hash in Ruby

Creating an md5 hash of a number, string, array, or hash in Ruby

I coding up the following pretty quickly and don't have time to really test it here at work, but it ought to do the job. Let me know if you find any issues with it and I'll take a look.

This should properly flatten out and sort the arrays and hashes, and you'd need to have to some pretty strange looking strings for there to be any collisions.

def createsig(body)
Digest::MD5.hexdigest( sigflat body )
end

def sigflat(body)
if body.class == Hash
arr = []
body.each do |key, value|
arr << "#{sigflat key}=>#{sigflat value}"
end
body = arr
end
if body.class == Array
str = ''
body.map! do |value|
sigflat value
end.sort!.each do |value|
str << value
end
end
if body.class != String
body = body.to_s << body.class.to_s
end
body
end

> sigflat({:a => {:b => 'b', :c => 'c'}, :d => 'd'}) == sigflat({:d => 'd', :a => {:c => 'c', :b => 'b'}})
=> true

Ruby/Rails: Hashing array of participant phone numbers to uniquely identify a group/MMS text conversation?

Yes, MD5 does give you that guarantee, unless someone is trying to attack your system. It is possible to create colliding MD5 hashes but they will never happen by accident.

So if in your situation the hash will only ever be benign (i.e. created by your code, not created by someone trying to mount an attack of some kind), then using MD5 is fine.

Or you could switch to using SHA256 instead of MD5 which doesn't have this risk associated with it.

ruby - Can I create a md5 hash of length 8?

MD5 creates 16-byte hashes. You can of course crop the string to eight characters, as with myString[0..7], but note that this not a valid MD5 hash any more.

Creating a hash where the keys are strings, values are numbers

Your expected hash is invalid. Therefore, it is impossible to get what you wrote that you want.

From your issue, it looks reasonable to expect the values to be array. In that case, you can do it like this:

["Melanie", "149", "Joe", "2", "16", "216", "Sarah"]
.slice_before(/[a-z]/i).map{|k, *v| [k, v.map(&:to_i)]}.to_h
# => {"Melanie"=>[149], "Joe"=>[2, 16, 216], "Sarah"=>[]}

With little modification, you can let the value be a number instead of an array when the array length is one, but that is not a good design; it would introduce exceptions.

What's the best way to generate a short hash string from a longer string

I often use a SHA has for this similar to the example you have. It's not guaranteed to be unique, but is usually good enough for most purposes:

require 'digest/sha1'
Digest::SHA1.hexdigest("#{user_id}-#{Time.now.to_i}-#{rand}")

The ruby UUID gem is another option.

But in your specific case since you're using redis, why not just use the redis INCR command? Then you can guarantee the uniqueness at least within your database. For example:

unique_key = $redis.incr('users:next')

How to turn into a hash what has been made into a string of a hash?

str = "{ H: 50, Q: 25, D: 10, N: 5, P: 1 }"

str.gsub(/(\S+): +(\d+)/).with_object({}) { |_,h| h[$1.to_sym] = $2.to_i }
#=> {:H=>50, :Q=>25, :D=>10, :N=>5, :P=>1}

This employs the form of String#gsub that takes an argument and no block, returning an enumerator that can be chained to Enumerator#with_object. This form of gsub merely generates matches; it makes no substitutions.

One advantage of this construct is that it avoids the creation of temporary arrays.

The regular expression can be written in free-spacing mode to make it self-documenting.

/
(\S+) # match 1+ characters other than whitespaces, save to capture group 1
:[ ]+ # match ':' followed by 1+ spaces
(\d+) # match 1+ digits, save to capture group 2
/x # free-spacing regex definition mode

Multiply the values of a hash by a number, and return 0 for the negative values

You can use Hash#transform_values (introduced in Ruby v2.4):

hash = {"year2020"=>"-2.0", "year2021"=>"3.0", "year2022"=>"1.0" }

hash.transform_values { |v| [2*v.to_f, 0].max }
#=> {"year2020"=>0, "year2021"=>6.0, "year2022"=>2.0}

How do I enter md5 block bytes in Ruby?

As already mentioned, use Array#pack to build a binary string then pass to a hash function. Working code:

require 'digest/md5'

input1= [
0x6165300e,0x87a79a55,0xf7c60bd0,0x34febd0b,0x6503cf04,0x854f709e,
0xfb0fc034,0x874c9c65,0x2f94cc40,0x15a12deb,0x5c15f4a3,0x490786bb,
0x6d658673,0xa4341f7d,0x8fd75920,0xefd18d5a].pack('I*')
p Digest::MD5.hexdigest input1
# "cee9a457e790cf20d4bdaa6d69f01e41"

Is `hash` on a number consistent within a single ruby process?

Yes, it is guaranteed to be the same within one Ruby process. Hash relies on this fact to guarantee unique keys. Otherwise long-lived processes could end up with duplicate hash keys when an object gets a new hash value.

Regarding implementation and memory locations, the implementation of hash is not guaranteed by Ruby. The only requirement is:

This function must have the property that a.eql?(b) implies a.hash ==
b.hash
.

In YARV, for example, many objects do not exist in memory at all (e.g. Fixnums) and are simply identified by a special object ID. x.object_id == x * 2 + 1 for any fixnum.



Related Topics



Leave a reply



Submit