Hash with default

I would like to make a hash like h2 with the default described by h in
one
line when I create the hash instead of 3 lines and 2 hashes like I did
here.
Any ideas?

h = Hash.new {|x,y| x[y] = y}
h2 = {“two”=>2,“three”=>3}
h.merge!(h2)
p h[“two”] #> 2
p h[“tree”] #> “tree”

Harry

If you want to do it in one line you could create a method which does
this, with whatever arguments you want to include.

On Fri, Mar 29, 2013 at 6:46 PM, Joel P. [email protected]
wrote:

If you want to do it in one line you could create a method which does
this, with whatever arguments you want to include.

Thanks. I was just wondering if there was a way to create the hash and
set
defaults at the same time.

h = Hash.new({“two”=>2,“three”=>3}){|x,y| y}

This does not work, but I want something like it.
I can make it myself if necessary, I just didn’t like the way it looked.
It seemed wasteful to use 2 hashes.

Harry

Well, if you really wanted to do it all in one go then this might work:

h = Hash.new {|x,y|
if some_condition
x[y] = ‘moose’
else
x[y] = y
end
}

On Fri, Mar 29, 2013 at 7:39 PM, 7stud – [email protected] wrote:

h = Hash.new {|h, k| k==‘two’ && h[k]=2 or k==‘three’ && h[k]=3 or
h[k]=nil}


Posted via http://www.ruby-forum.com/.

What!?

h = Hash.new {|h, k| k==‘two’ && h[k]=2 or k==‘three’ && h[k]=3 or
h[k]=nil}

The one line requirement should be dropped. Clarity trumps brevity
every time.

On 29/03/2013, at 8:32 PM, Harry K. [email protected] wrote:

Harry

You can set a default… but you can’t set the default to be a piece
of code that can change default behaviour. By the way, the first line of
your program doesn’t work. You know that, right?

To get what you want, you can do this:

h = {}; def h.; self.has_key?(key) ? super(key) : key; end

or alternatively:

h = {}
(class << h; self; end).send(:define_method, :[]){|key|
self.has_key?(key) ? super(key) : key}

Julian

On 30/03/2013, at 2:45 AM, Julian L. [email protected]
wrote:

h = {}; def h.; self.has_key?(key) ? super(key) : key; end

or alternatively:

h = {}
(class << h; self; end).send(:define_method, :[]){|key| self.has_key?(key) ?
super(key) : key}

Julian

Sorry, forgot to set your data in there, too:

h = {“two”=>2,“three”=>3}; def h.; self.has_key?(key) ?
super(key) : key; end

There you go. Not really on one line, but oh well, you wanted different
behaviour than the default hash behaviour for defaults.

Julian

On 29 March 2013 15:53, Julian L. [email protected] wrote:

h = {“two”=>2,“three”=>3}; def h.; self.has_key?(key) ? super(key) :
key; end

Why not use the block to Hash.new instead of overriding #[] ?

h = Hash.new { |h,k| k }
=> {}
h[“one”]
=> “one”
h
=> {}

Note this is different than using h[k] = k in the block.

As for the original question, I think you can rely on default_proc and
get around the fact it doesn’t return the receiver pretty easily.

h = { “two” => 2, “three” => 3 }.tap { |o| o.default_proc = lambda { |h, k| k }
}
=> {“two”=>2, “three”=>3}
h
=> {“two”=>2, “three”=>3}
h[“two”]
=> 2
h[“five”]
=> “five”
h
=> {“two”=>2, “three”=>3}

Having said that, I don’t see any benefit in trying to get it down to
a single line and sacrificing readability. You can define h to be what
you want, then on a separate line just call #default_proc=.

On 30/03/2013, at 3:02 AM, Adam P. [email protected] wrote:

=> {}

h[“two”]
=> 2
h[“five”]
=> “five”
h
=> {“two”=>2, “three”=>3}

Having said that, I don’t see any benefit in trying to get it down to
a single line and sacrificing readability. You can define h to be what
you want, then on a separate line just call #default_proc=.

Sorry. I apologise. My information was outdated, and I stand corrected!

On Fri, Mar 29, 2013 at 10:32 AM, Harry K. [email protected]
wrote:

I would like to make a hash like h2 with the default described by h in one
line when I create the hash instead of 3 lines and 2 hashes like I did here.
Any ideas?

h = Hash.new {|x,y| x[y] = y}

I don’t think this is a good implementation of a default value: you add
items to the hash without any need because the return value of h[x]
where x
is not stored in the Hash does not change but you incur the overhead of
storing the value in the Hash (which may include memory reallocation
etc.).

h2 = {“two”=>2,“three”=>3}
h.merge!(h2)
p h[“two”] #> 2
p h[“tree”] #> “tree”

What’s wrong with

h = Hash.new {|x,y| x[y] = y}.merge!(“two”=>2, “three”=>3)

? You can even omit the brackets:

h = Hash.new {|x,y| x[y] = y}.merge! “two”=>2, “three”=>3

If you have just one usage location where you need the default
replacement
this would be an alternative:

h = {“two”=>2,“three”=>3}

h.fetch(key) {|y| h[y] = y}

Kind regards

robert

Thanks, everybody.

I like this because it does what I want and it is easy for me to read.

h = Hash.new {|x,y| y}.merge!(“two”=>2, “three”=>3)
p h[“two”]
p h[“three”]
p h[“tree”]
p h

Harry