开发者

Most efficient way to map a specific string into a hash in Ruby

I'm new to Ruby and am working on a CLI application that parses some reports of mine. I would like to figure out the most efficient way to achieve the following with this line:

MAXCONN: 2000, MAXSSL_CONN: 500, PLAINCONN: 34, AVAILCONN: 1966, IDLECONN: 28, SSLCONN: 0, AVAILSSL: 500

I would like to map this into a hash accordingly:

{ :maxconn => 2000, :maxssl_conn => 500, :plainconn => 34, :availconn => 1966, :idleconn => 28, :sslconn => 0, :availssl => 500 }

The only way I can think to do this i开发者_StackOverflows to split at the comma and then again at the semi-colon and map them.

I have a sneaking suspicion there may be some Ruby magic to achieve this in a more efficient and less cumbersome way.

Any input and or tricks / tips would be appreciated as I have a feeling I'll be approaching problems like this relatively often.


We combine the technique for converting a bunch of key-value pairs into a hash

Hash[[[k1, v1], [k2, v2], ...]] #=> { k1 => v1, k2 => v2, ... }

with the regular expression method String#scan, which passes through a string and collects matches in an array, to get

Hash[reports.scan(/(\w+): (\w+)/).map { |(first, second)| [first.downcase.to_sym, second.to_i] }]

This also uses a block with Enumerable#map that interprets arrays as pairs of (first, second) elements in the argument list, extracts these into new elements, and applies conversions to them so as to tailor the resulting hash to your example's specifications (otherwise, you just get a hash of strings mapping to strings).


hash = {}
input.scan /(\w)+\:(\d+)\,/ do |key, val|
  hash[key.downcase.to_sym] = val.to_i
end 

Seems like the most obvious.

You could do (with some caveats) this:

hash = Hash[*eval(string).map{|k,v| [k.downcase.to_sym, v]}.flatten]

But that's really forcing a one-liner where it shouldn't be.

Of course splitting it isn't a horrible idea:

hash = input.split(",").each_with_object({}) do |str, h| 
  k,v = str.split(":")
  h[k.downcase.to_sym] = v.to_i
end


If you are using ruby1.9, you do not even need to parse that text because ruby1.9 accepts hash literals in the form {symbol: value} when the key is a symbol. Simply, do this:

eval("{#{your_string.downcase}}")


Write the code first, then optimize it

If your code causes a bottleneck on your implementation of Ruby, the first thing you'd have to do is work out if it's the string splitting, or the hash creation, or adding your new hash to whatever array it's in (this is the step I'd be most worried about!), that's causing the bottleneck.

Write functional programming style code - it's usually cleaner, and sometimes faster

With regards to adding your new hash to the array it's in, generally you shouldn't do

array_of_hashes = []
lines.each do |line|
  hash = create_hash(line)
  array_of_hashes << hash
end

instead, do

array_of_hashes = lines.map do |line|
  hash = create_hash(line)
  hash
end

The latter is generally better performing, but regardless of that, it's cleaner code, so it's not a premature optimization.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜