Is there an idiom for mass-populating Hash keys?


#1

Hello, good folk of ruby-talk.

I was wondering whether there’s a Ruby
idiom to mass-populate keys of a Hash.

I’m coding a graph class supporting labeled vertices, and I want to
represent this relationship as a @vertices Hash, with keys being the
actual vertices and values being their labels – initially all nil:

class Graph
def initialize enum
@vertices = {}
enum.each { |vertex| @vertices[vertex] = nil }
end
end

Is there a more elegant way to take an enum
and turn it into nil-referencing Hash keys?

— Shot


#2

On Mar 29, 2009, at 10:05 AM, Shot (Piotr S.) wrote:

def initialize enum
@vertices = {}
enum.each { |vertex| @vertices[vertex] = nil }
end
end

Is there a more elegant way to take an enum
and turn it into nil-referencing Hash keys?

dunno if it’s really better but this is one approach:

cfp:~ > cat a.rb

hash = {}

enum = (‘a’…‘z’)

hash.update Hash[*enum.zip([])]

p hash
cfp:~ > ruby a.rb
{[“e”, nil]=>[“f”, nil], [“o”, nil]=>[“p”, nil], [“y”, nil]=>[“z”,
nil], [“i”, nil]=>[“j”, nil], [“s”, nil]=>[“t”, nil], [“c”,
nil]=>[“d”, nil], [“m”, nil]=>[“n”, nil], [“w”, nil]=>[“x”, nil],
[“g”, nil]=>[“h”, nil], [“q”, nil]=>[“r”, nil], [“a”, nil]=>[“b”,
nil], [“k”, nil]=>[“l”, nil], [“u”, nil]=>[“v”, nil]}

a @ http://codeforpeople.com/


#3

On Sun, Mar 29, 2009 at 12:05 PM, Shot (Piotr S.)
removed_email_address@domain.invalidwrote:

def initialize enum
@vertices = {}
enum.each { |vertex| @vertices[vertex] = nil }
end
end

Is there a more elegant way to take an enum
and turn it into nil-referencing Hash keys?

Why bother? The only reason I can thing of is that you want to use
@vertices.keys to get the collection of vertices, but why be indirect.

class Graph
def initialize(enum)
@vertices = enum
@labels = {}
end
end

@labels[anything] will return nil if anything isn’t a key.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale


#4

Rick DeNatale:

On Sun, Mar 29, 2009 at 12:05 PM, Shot (Piotr S.) removed_email_address@domain.invalidwrote:

class Graph
def initialize enum
@vertices = {}
enum.each { |vertex| @vertices[vertex] = nil }
end
end

Why bother? The only reason I can thing of is that you want to use
@vertices.keys to get the collection of vertices, but why be indirect.

class Graph
def initialize(enum)
@vertices = enum
@labels = {}
end
end

@labels[anything] will return nil if anything isn’t a key.

Right, I was thinking about this approach on and off all day today,
actually. :slight_smile: The catch is I’ll be doing various things to this graph,
like merging vertices together, grouping them by their labels (graph
colouring), and doing similar operations on (labeled) edges.

While I do like the cleanliness of the approach with @vertices being
just a Set, @edges being just a Set of two-element Sets, and there being
two additional Hashes for vertex and edge labels, I’m not sure I want
the overhead of making sure there aren’t any leftover keys in the label
Hashes after the graph drops some of its edges/vertices – in other
words, anytime I delete a vertex or an edge I’d have to delete it from
two places (either that, or anytime I query the labels I’d have to make
sure I’m filtering out no-longer-existing vertices/edges – which is even
uglier).

Note: I do know about GRATR, but it seems unmaintained; I found
(granted, minor) bugs in it by simply requiring it with warnings
enabled, and it requires (again, minor) patching to get it working
with Ruby 1.9, but my patches to fix both are ignored (and there haven’t
been a relase for a year and a half). I would also use just a tiny
fraction of GRATR’s functionality, so it’s simpler for me to have my
own Graph class (and be able to easily RubyInline parts of it if/when
I need the performance).

— Shot


#5

Shot (Piotr S.) wrote:

The catch is I’ll be doing various things to this graph,
like merging vertices together, grouping them by their labels (graph
colouring), and doing similar operations on (labeled) edges.

Try providing a default_proc to Hash.new:

Hash.new {|h,k| h[k] = nil }

Now previously unregistered vertices will be registered upon hash access
(Hash#[]). To illustrate this technique, consider this “dynamic
programming” based Fibonacci sequence implementation:

fib = Hash.new {|h,k| k < 2 ? 1 : h[k-1] + h[k-2] }

p 0 => fib[0]
p 1 => fib[1]
p 5 => fib[5]
p :cache => fib


#6

Suraj K. wrote:

consider this “dynamic programming” based Fibonacci sequence implementation:

fib = Hash.new {|h,k| k < 2 ? 1 : h[k-1] + h[k-2] }

Whoops, I forgot to store the computed value in the hash!

fib = Hash.new {|h,k| h[k] = k < 2 ? 1 : h[k-1] + h[k-2] }

Now it should work. Sigh :slight_smile: