Forum: Ruby Is there an idiom for mass-populating Hash keys?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Shot (Piotr S.) (Guest)
on 2009-03-29 20:07
(Received via mailing list)
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
Ara H. (Guest)
on 2009-03-29 20:17
(Received via mailing list)
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/
Rick D. (Guest)
on 2009-03-29 20:57
(Received via mailing list)
On Sun, Mar 29, 2009 at 12:05 PM, Shot (Piotr S.)
<removed_email_address@domain.invalid>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?
>

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
Shot (Piotr S.) (Guest)
on 2009-03-30 00:32
(Received via mailing list)
Rick DeNatale:

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

>> 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. :) 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
Suraj K. (Guest)
on 2009-03-31 03:15
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
Suraj K. (Guest)
on 2009-03-31 03:18
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 :-)
This topic is locked and can not be replied to.