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)
impliesa.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
Ruby/Rails Using || to Determine Value, Using an Empty String Instead of a Nil Value
How to Do a Regex Search in Nokogiri for Text That Matches a Certain Beginning
How to Generate the First N Prime Numbers
Rails 4 Migration: Has_And_Belongs_To_Many Table Name
Bundle Command Not Found in Linux Debian
Mapping Values from Two Array in Ruby
How to Inspect the Methods of a Ruby Object
How to Reference an Embedded Document in Mongoid
Installing Ruby 2.3.X on Ubuntu 18.04 Is Causing an Error by the End of the Installation Process
How to Make a Rake Task Run After All Other Tasks? (I.E. a Rake Afterbuild Task)
How to Remove 4 Byte Utf-8 Characters in Ruby
Are Bundle Exec and Require 'Bundler/Setup' Equivalent