Special Hash Constructors

Discussion in 'Ruby' started by Robert Klemme, Feb 6, 2009.

  1. 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
     
    Robert Klemme, Feb 6, 2009
    #1
    1. Advertising

  2. On Fri, Feb 6, 2009 at 9:09 AM, Robert Klemme
    <> wrote:
    >
    > 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


    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
     
    Christopher Dicely, Feb 6, 2009
    #2
    1. Advertising

  3. Wow I like that. This is what I end up doing:

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

    J

    On 07/02/2009, at 4:09 AM, Robert Klemme wrote:

    >
    > 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
    >
     
    Julian Leviston, Feb 7, 2009
    #3
  4. * Robert Klemme <> (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
     
    Simon Krahnke, Feb 7, 2009
    #4
  5. Robert Klemme

    Tom Link Guest

    > def Hash.with(default=3Dnil)
    > =A0 new { | h, k | h[k] =3D default.dup }
    > end


    Not so good:

    > h =3D Hash.with(0)
    > h[1]

    TypeError: can't dup Fixnum

    I personally would appreciate a special constructor for Arrays.
     
    Tom Link, Feb 7, 2009
    #5
  6. On Sat, Feb 7, 2009 at 5:34 AM, Simon Krahnke <> wrote:
    > * Robert Klemme <> (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.
     
    Jesús Gabriel y Galán, Feb 7, 2009
    #6
  7. On 07.02.2009 11:09, Jesús Gabriel y Galán wrote:
    > On Sat, Feb 7, 2009 at 5:34 AM, Simon Krahnke <> 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
     
    Robert Klemme, Feb 7, 2009
    #7
  8. Robert Klemme

    Trans Guest

    On Feb 6, 12:09=A0pm, Robert Klemme <> wrote:
    > Hi there,
    >
    > we frequently do
    >
    > ha =3D Hash.new {|h,k| h[k] =3D []}
    >
    > 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
    > =A0 =A0new {|h,k| h[k] =3D []}
    > end
    >
    > While we're at it, we might as well add
    >
    > def Hash.with_hashes
    > =A0 =A0new {|h,k| h[k] =3D Hash.new(&h.default_proc)}
    > end


    I've been using the name #autonew for this last one.

    Also @Tom Link

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

    T.
     
    Trans, Feb 7, 2009
    #8
  9. Robert Klemme

    Tom Link Guest

    > =A0 def Hash.with(default=3Dnil)
    > =A0 =A0 begin


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

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

    ...

    This method isn't capable of emulating the with_hashes method proposed
    by Robert K though, is it?
     
    Tom Link, Feb 7, 2009
    #9
  10. On 07.02.2009 11:26, Trans wrote:
    >
    > On Feb 6, 12:09 pm, Robert Klemme <> wrote:
    >> 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

    >
    > 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


    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
     
    Robert Klemme, Feb 7, 2009
    #10
  11. Robert Klemme

    Pit Capitain Guest

    2009/2/7 Tom Link <>:
    > 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
     
    Pit Capitain, Feb 7, 2009
    #11
  12. * Tom Link <> (11:44) schrieb:

    >>   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?


    I think that's special enough to have its own method.

    mfg, simon .... l
     
    Simon Krahnke, Feb 7, 2009
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Dave Rudolf
    Replies:
    12
    Views:
    8,331
    Martijn Lievaart
    Feb 6, 2004
  2. Jeremy Smith
    Replies:
    2
    Views:
    603
    Jeremy Smith
    Aug 3, 2006
  3. Jess
    Replies:
    5
    Views:
    615
    Ron Natalie
    Jun 7, 2007
  4. Peng Yu
    Replies:
    5
    Views:
    403
    Juha Nieminen
    Sep 19, 2008
  5. rp
    Replies:
    1
    Views:
    557
    red floyd
    Nov 10, 2011
Loading...

Share This Page