Ruby: How can I use Hash for multiple keys?

I take 5 lines (protocol, source IP and port, IP address and destination port) and use them to store some values ​​in a hash. The problem is that if the IP or ports are switched between the source and destination, it is assumed that the key will be the same.

If I were doing this in C # / Java / no matter what, I would have to create a new class and overwrite the hashcode () / equals () methods, but this seems like a mistake, prone to what I read about it and Me I was wondering if there is a better alternative here.

+4
source share
3 answers

I directly copy the paragraph from "Ruby 1.9 Programming":

The hash keys must respond to the hash message, returning a hash code, and the hash code for the given key should not change. Keys used in hashes should also be comparable using eql? . If eql? returns true for two keys, then these keys must also have the same hash code. This means that some classes (such as Array and hash ) cannot be conveniently used as keys, because their hash values ​​may vary depending on their contents.

Thus, you can create your hash as something like ["#{source_ip} #{source_port}", "#{dest_ip} #{dest_port}", protocol.to_s].sort.join.hash so that the result is identical when switching source and destination.

For instance:

 source_ip = "1.2.3.4" source_port = 1234 dest_ip = "5.6.7.8" dest_port = 5678 protocol = "http" def make_hash(s_ip, s_port, d_ip, d_port, proto) ["#{s_ip} #{s_port}", "#{d_ip} #{d_port}", proto.to_s].sort.join.hash end puts make_hash(source_ip, source_port, dest_ip, dest_port, protocol) puts make_hash(dest_ip, dest_port, source_ip, source_port, protocol) 

This will result in the same hash, even if the arguments are in a different order between the two calls. The proper encapsulation of this functionality in a class is left as an exercise for the reader.

+4
source

I think this is what you mean ...

 irb(main):001:0> traffic = [] => [] irb(main):002:0> traffic << {:src_ip => "10.0.0.1", :src_port => "9999", :dst_ip => "172.16.1.1", :dst_port => 80, :protocol => "tcp"} => [{:protocol=>"tcp", :src_ip=>"10.0.0.1", :src_port=>"9999", :dst_ip=>"172.16.1.1", :dst_port=>80}] irb(main):003:0> traffic << {:src_ip => "10.0.0.2", :src_port => "9999", :dst_ip => "172.16.1.1", :dst_port => 80, :protocol => "tcp"} => [{:protocol=>"tcp", :src_ip=>"10.0.0.1", :src_port=>"9999", :dst_ip=>"172.16.1.1", :dst_port=>80}, {:protocol=>"tcp", :src_ip=>"10.0.0.2", :src_port=>"9999", :dst_ip=>"172.16.1.1", :dst_port=>80}] 

The next, somewhat related question is how to store the IP address. You probably want to use the IPAddr object instead of a simple string to make it easier to sort the results.

0
source

You can use the following code:

 def create_hash(prot, s_ip, s_port, d_ip, d_port, value, x = nil) if x x[prot] = {s_ip => {s_port => {d_ip => {d_port => value}}}} else {prot => {s_ip => {s_port => {d_ip => {d_port => value}}}}} end end # Create a value h = create_hash('www', '1.2.4.5', '4322', '4.5.6.7', '80', "Some WWW value") # Add another value create_hash('https', '1.2.4.5', '4562', '4.5.6.7', '443', "Some HTTPS value", h) # Retrieve the values puts h['www']['1.2.4.5']['4322']['4.5.6.7']['80'] puts h['https']['1.2.4.5']['4562']['4.5.6.7']['443'] 
0
source

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


All Articles