Forum: Ruby Special Hash Constructors

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.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-02-06 18:10
(Received via mailing list)
Hi there,

we frequently do

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

so we can later do

ha[any_key] << anything

Since the idiom is so common, what does everybody think of putting it
into the standard library:

def Hash.with_arrays
   new {|h,k| h[k] = []}
end

While we're at it, we might as well add

def Hash.with_hashes
   new {|h,k| h[k] = Hash.new(&h.default_proc)}
end

Kind regards

  robert
D7463bd611f227cfb2ef4da4a978a203?d=identicon&s=25 Christopher Dicely (Guest)
on 2009-02-06 18:45
(Received via mailing list)
On Fri, Feb 6, 2009 at 9:09 AM, Robert Klemme
<shortcutter@googlemail.com> wrote:
>
>  new {|h,k| h[k] = Hash.new(&h.default_proc)}
> end
>
> Kind regards
>
>        robert

Rather than making class methods on Hash to create special hashes like
this, why not make subclasses, so you can attach specialized instance
methods that make sense only for these kinds of hashes. For instance,
for the Hash-of-Hashes form, you might want a method that "rotates"
the Hash into a new Hash-of-Hashes like this:

def rotate
  res = HashOfHashes.new
  each { |ok, ov| ov.each { |ik, iv| res[ik][ok] = iv } }
  res
end
3131fcea0a711e5ad89c8d49cc9253b4?d=identicon&s=25 Julian Leviston (Guest)
on 2009-02-07 01:39
(Received via mailing list)
Wow I like that. This is what I end up doing:

ha = {}
(ha[any_key] ||= []) << anything

J
1d53b088a989e069b94597c282eebbbc?d=identicon&s=25 Simon Krahnke (Guest)
on 2009-02-07 05:35
(Received via mailing list)
* Robert Klemme <shortcutter@googlemail.com> (18:05) schrieb:

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

> Since the idiom is so common, what does everybody think of putting it
> into the standard library:

Why not

def Hash.with(default=nil)
  new { | h, k | h[k] = default.dup }
end

> While we're at it, we might as well add
>
> def Hash.with_hashes
>   new {|h,k| h[k] = Hash.new(&h.default_proc)}
> end

I'm too tired for that. Does that create Hash with a default proc that
is the same as the one you specify right there?

mfg,                   simon .... l
9b905791cbdbb1af35b65e02c3217e23?d=identicon&s=25 Tom Link (Guest)
on 2009-02-07 07:17
(Received via mailing list)
> def Hash.with(default=nil)
>   new { | h, k | h[k] = default.dup }
> end

Not so good:

> h = Hash.with(0)
> h[1]
TypeError: can't dup Fixnum

I personally would appreciate a special constructor for Arrays.
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 Jesús Gabriel y Galán (Guest)
on 2009-02-07 11:10
(Received via mailing list)
On Sat, Feb 7, 2009 at 5:34 AM, Simon Krahnke <overlord@gmx.li> wrote:
> * Robert Klemme <shortcutter@googlemail.com> (18:05) schrieb:

>> def Hash.with_hashes
>>   new {|h,k| h[k] = Hash.new(&h.default_proc)}
>> end
>
> I'm too tired for that. Does that create Hash with a default proc that
> is the same as the one you specify right there?

Yes, it achieves having infinitely nested hashes:

irb(main):001:0> def Hash.with_hashes
irb(main):002:1> new {|h,k| h[k] = Hash.new(&h.default_proc)}
irb(main):003:1> end
=> nil
irb(main):004:0> h = Hash.with_hashes
=> {}
irb(main):005:0> h[1][2][3] = true
=> true
irb(main):006:0> h
=> {1=>{2=>{3=>true}}}

I agree that it would be nice to have them in the standard library,
but maybe Hash.of_hashes and Hash.of_arrays would be better names?

Jesus.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-02-07 11:25
(Received via mailing list)
On 07.02.2009 11:09, Jesús Gabriel y Galán wrote:
> On Sat, Feb 7, 2009 at 5:34 AM, Simon Krahnke <overlord@gmx.li> wrote:

> I agree that it would be nice to have them in the standard library,
> but maybe Hash.of_hashes and Hash.of_arrays would be better names?

Yes, probably.  I'm not religious about the names.  My point was simply
that this is so often used that we might want to have it in the standard
library.

Cheers

  robert
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Thomas Sawyer (7rans)
on 2009-02-07 11:27
(Received via mailing list)
On Feb 6, 12:09 pm, Robert Klemme <shortcut...@googlemail.com> wrote:
> Since the idiom is so common, what does everybody think of putting it
> end
I've been using the name #autonew for this last one.

Also @Tom Link

  def Hash.with(default=nil)
    begin
      new { | h, k | h[k] = default.dup }
    rescue TypeError
      new(default)  # same as { | h, k | h[k] = default }
    end
  end

T.
9b905791cbdbb1af35b65e02c3217e23?d=identicon&s=25 Tom Link (Guest)
on 2009-02-07 11:48
(Received via mailing list)
>   def Hash.with(default=nil)
>     begin

I think we have to insert a check for "dupability" here:

        default.dup
>       new { | h, k | h[k] = default.dup }
...

This method isn't capable of emulating the with_hashes method proposed
by Robert K though, is it?
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-02-07 14:20
(Received via mailing list)
On 07.02.2009 11:26, Trans wrote:
>> ha[any_key] << anything
>> def Hash.with_hashes
>     rescue TypeError
>       new(default)  # same as { | h, k | h[k] = default }
>     end
>   end

Where's the point of the rescue clause?  The error will show up much
later, i.e. after the method has returned.

Also, as Tom pointed out, this is not the same as what I proposed - not
even similar.

Regards

  robert
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Thomas Sawyer (7rans)
on 2009-02-07 16:34
(Received via mailing list)
On Feb 7, 8:18 am, Robert Klemme <shortcut...@googlemail.com> wrote:

> Where's the point of the rescue clause?  The error will show up much
> later, i.e. after the method has returned.

Why would the error show later? It is just so one could pass a
immutable, like 0 to #with without raising an error b/c it doesn't
respond to #dup.

> Also, as Tom pointed out, this is not the same as what I proposed - not
> even similar.

It's not?

  Hash.with([])

is not the same as

  Hash.with_arrays

?
50b2daf0e7666574579b9edaf8f2b69a?d=identicon&s=25 Pit Capitain (Guest)
on 2009-02-07 16:38
(Received via mailing list)
2009/2/7 Tom Link <micathom@gmail.com>:
> Not so good:
> TypeError: can't dup Fixnum

I often use

  class Hash
    def self.new_with
      new { |h, k| h[k] = yield }
    end
  end

  Hash.new_with { [] }

which works with Arrays and Fixnums, though it isn't needed for the
latter.

Regards,
Pit
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2009-02-07 17:40
(Received via mailing list)
On 07.02.2009 16:32, Trans wrote:
>
> On Feb 7, 8:18 am, Robert Klemme <shortcut...@googlemail.com> wrote:
>
>> Where's the point of the rescue clause?  The error will show up much
>> later, i.e. after the method has returned.
>
> Why would the error show later? It is just so one could pass a
> immutable, like 0 to #with without raising an error b/c it doesn't
> respond to #dup.

The code block is not executed when you invoke Hash.with - hence there
can't be an error.  When you need it the rescue block is not there as
the block is called from a different context.

>
> ?
>

It's closer than I initially thought.  But: I wanted these two special
methods and not yet another generic method.  For that, we have the
original Hash.new already.  Your version still needs an argument.  Since
I see that we are using an Array most of the time anyway that can be
coded into the method.  No need for another generic approach IMHO.

Cheers

  robert
1d53b088a989e069b94597c282eebbbc?d=identicon&s=25 Simon Krahnke (Guest)
on 2009-02-07 19:05
(Received via mailing list)
* Tom Link <micathom@gmail.com> (11:44) schrieb:

> by Robert K though, is it?
I think that's special enough to have its own method.

mfg,                    simon .... l
1d53b088a989e069b94597c282eebbbc?d=identicon&s=25 Simon Krahnke (Guest)
on 2009-02-07 19:35
(Received via mailing list)
* Robert Klemme <shortcutter@googlemail.com> (17:35) schrieb:

> It's closer than I initially thought.  But: I wanted these two special
> methods and not yet another generic method.  For that, we have the
> original Hash.new already.  Your version still needs an argument.  Since
> I see that we are using an Array most of the time anyway that can be
> coded into the method.  No need for another generic approach IMHO.

The difference between the existing and the new generic is the
assignment. I see the block form of new most often because some mutable
object should be assigned on read.

mfg,                     simon .... l
This topic is locked and can not be replied to.