Forum: Ruby what is the ruby way to do this?

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.
akonsu (Guest)
on 2005-11-23 00:08
(Received via mailing list)
hello,

i am still learning. in the below code @attributes is a hash table. i
want to add a new value 'a' for a key represented by 'a.key'. i also
want to group values with the same keys in to arrays. thanks for any
help.

konstantin

if @attributes.has_key?(a.key)
  if @attributes[a.key].is_a?(Array)
    @attributes[a.key] << a
  else
    @attributes[a.key] = [@attributes[a.key], a]
  end
else
  @attributes[a.key] = a
end
akonsu (Guest)
on 2005-11-23 00:08
(Received via mailing list)
sorry, forgot to phrase the question. the question is is there a way to
make this code more compact and pretty?
mrkode (Guest)
on 2005-11-23 00:24
(Received via mailing list)
On 11/22/05, ako... <removed_email_address@domain.invalid> wrote:
> if @attributes.has_key?(a.key)
>
Pardon my question, but isn't the whole point of hashes that every key
is
unique?
lyndon.samson (Guest)
on 2005-11-23 00:28
(Received via mailing list)
$hash = {}

def add(key, val)
if $hash.has_key?(key)
if $hash[key].is_a?(Array)
$hash[key] << val
else
$hash[key] = [$hash[key], val]
end
else
$hash[key] = val
end
end

def add2(key, val)
if $hash.has_key?(key)
$hash[key].to_a << val
else
$hash[key] = val.to_a
end
end

key = "a"
val = "aval"
add2(key, val)
puts $hash.inspect

key = "a"
val = "aval2"
add2(key, val)
puts $hash.inspect
lyndon.samson (Guest)
on 2005-11-23 00:32
(Received via mailing list)
and this monstrosity, which isn't in the spirit of ruby... :-)

def add3(key, val)
$hash[key] = ( $hash[key] == nil ) ? val.to_a : $hash[key] << val
end
akonsu (Guest)
on 2005-11-23 00:32
(Received via mailing list)
yes, this is the point of hashes. in my program, i have attributes with
names (keys). i want to collect these attributes in to a data
structure. attributes with the same names form an array. like in a HTTP
POST form, if you have fields with the same names they are treated as
an array.
leavengood (Guest)
on 2005-11-23 00:36
(Received via mailing list)
On 11/22/05, ako... <removed_email_address@domain.invalid> wrote:
>   if @attributes[a.key].is_a?(Array)
>     @attributes[a.key] << a
>   else
>     @attributes[a.key] = [@attributes[a.key], a]
>   end
> else
>   @attributes[a.key] = a
> end

This is a fairly standard Ruby idiom (a hash of arrays):

(@attributes[a.key]||=[])<<a

What the above is doing is setting the entry for a.key to an empty
array if nothing exists, otherwise it will return the array already at
that location. Then the element a is added to that array.

Ryan
leavengood (Guest)
on 2005-11-23 00:41
(Received via mailing list)
On 11/22/05, ako... <removed_email_address@domain.invalid> wrote:
> yes, this is the point of hashes. in my program, i have attributes with
> names (keys). i want to collect these attributes in to a data
> structure. attributes with the same names form an array. like in a HTTP
> POST form, if you have fields with the same names they are treated as
> an array.

In my opinion it is better to just put all the attributes into an
array (which is what my code does), even the single ones, that way you
can treat all the hashtable entries the same way (since they will all
be arrays.)

Ryan
lyndon.samson (Guest)
on 2005-11-23 00:41
(Received via mailing list)
And finally I get to

def add4(key, val)
$hash[key]= $hash[key].to_a << val
end

These mean your values are allways arrays, but thats no problem right?
kennethkunz (Guest)
on 2005-11-23 00:45
(Received via mailing list)
Konstantin,

When you have a single attribute associated with a key, is it
acceptable to have it in a one-element array? If so, you could do
something like:

@attributes = {}
....
@attributes[a.key] ||= []
@attributes[a.key] << a

Or, if you don't mind having empty keys return an empty array instead
of nil, you could do:

@attributes = Hash.new([])
....
@attributes[a.key] << a

Cheers,
Ken
akonsu (Guest)
on 2005-11-23 00:45
(Received via mailing list)
thank you. this assumes that the hash's default value is nil. but this
is a good enough assumption for my purposes. i was hoping to avoid
creating one-element arrays and still have the simplicity of a single
line solution but i guess this cant be done. thanks for your help.

konstantin
billk (Guest)
on 2005-11-23 00:49
(Received via mailing list)
Hi,

From: "ako..." <removed_email_address@domain.invalid>
>    @attributes[a.key] = [@attributes[a.key], a]
>  end
> else
>  @attributes[a.key] = a
> end

An alternate approach might be:

@attributes = Hash.new {|h,k| h[k] = Array.new}

This will automatically create arrays to hold your keys, on demand.

Now you can just say:

@attributes["whatever"] << "something"
@attributes["foo"] << 123
@attributes["foo"] << 456

@attributes.inspect
{"foo"=>[123, 456], "whatever"=>["something"]}


Hope this helps,

Regards,

Bill
akonsu (Guest)
on 2005-11-23 00:53
(Received via mailing list)
thanks. this form of Hash creation with blocks is not documented in
http://www.rubycentral.com/book/ref_c_hash.html. would you point me to
the documentation for this?
caleb (Guest)
on 2005-11-23 00:57
(Received via mailing list)
Note that a "Ruby" hint would be to get rid of your "is_a?",
preferring to use "respond_to?" instead.

You could get fancier and just call "<<" on everything, catching
exceptions and handling them for objects that don't implement that
method.

Caleb
mvette13 (Guest)
on 2005-11-23 00:57
(Received via mailing list)
Personally, I would keep every element of the hash an array. You can do
that
like so...
def add4( key, value )
@hsh[key] = @hsh[key].to_a<<value
end


if you must keep entries in the hash that only have one value as single
elements and not as arrays..
def add5( key, value )
@hsh[key] = @hsh[key]?@hsh[key].to_a<<value:value
end
desmarm (Guest)
on 2005-11-23 01:01
(Received via mailing list)
ako... wrote:

>thanks. this form of Hash creation with blocks is not documented in
>http://www.rubycentral.com/book/ref_c_hash.html. would you point me to
>the documentation for this?
>
>
>
See ri Hash.new.

Regards,
Matthew
desmarm (Guest)
on 2005-11-23 01:01
(Received via mailing list)
Ken Kunz wrote:

>
>
Careful with this one.  When you do this:

Hash.new([])

you set the default valued returned by the hash to an array.  The
problem is that it will always return the same array.  So in the example
provided above you will end up with an empty hash for @attributes.

What you really want is the default block style:
Hash.new{|hash, key| hash[key] = []}

This will create a new array for each key.

It's an extremely sneaky little problem.

Regards,
Matthew
mental (Guest)
on 2005-11-23 01:09
(Received via mailing list)
Quoting Caleb T. <removed_email_address@domain.invalid>:

> You could get fancier and just call "<<" on everything, catching
> exceptions and handling them for objects that don't implement
> that method.

It's better to use respond_to? -- if you get a NameError, you can't
distinguish between the object itself not responding to :"<<" and
something deep in the bowels of its :"<<" implementation not
responding to :"<<".

-mental
akonsu (Guest)
on 2005-11-23 01:09
(Received via mailing list)
sorry, what is 'ri'?
james_b (Guest)
on 2005-11-23 01:17
(Received via mailing list)
Bill K. wrote:

> @attributes["foo"] << 456
>
> @attributes.inspect
> {"foo"=>[123, 456], "whatever"=>["something"]}



And, mixing some of the approaches shown:


@attributes = {}


# Assumes the given object quacks on 'key'
def @attributes.<<( keyed_obj )
   (self[keyed_obj.key]||=[])<<keyed_obj
end


@attributes << a1
@attributes << a2
@attributes << a3



James

--

http://www.ruby-doc.org       - Ruby Help & Documentation
http://www.artima.com/rubycs/ - Ruby Code & Style: Writers wanted
http://www.rubystuff.com      - The Ruby Store for Ruby Stuff
http://www.jamesbritt.com     - Playing with Better Toys
http://www.30secondrule.com   - Building Better Tools
desmarm (Guest)
on 2005-11-23 01:17
(Received via mailing list)
ako... wrote:

>sorry, what is 'ri'?
>
>
ri is a commend line program that may or may not have been installed
with your distribution of ruby.  It's a viewer for the documentation
that was (hopefully) also installed with your disctribution of ruby.

If you type "ri Hash.new" it will display information on the class
method Hash.new.  If you were to use the form "ri Hash#keys" then you
weould be requesting information about the instance method keys that may
be called on a hash object.

Try it, and if you don't have it installed then someone can help you get
it set up.

Regards,
Matthew
akonsu (Guest)
on 2005-11-23 01:29
(Received via mailing list)
> @attributes = {}
>
> # Assumes the given object quacks on 'key'
> def @attributes.<<( keyed_obj )
>   (self[keyed_obj.key]||=[])<<keyed_obj
> end
>
> @attributes << a1
> @attributes << a2
> @attributes << a3

this is something i have never seen. would you explain the 'def' line
above? is this the same as class << @attributes; def << ...; end ?
jeff.darklight (Guest)
on 2005-11-23 03:10
(Received via mailing list)
It's defining the << operator on the @attributes object

j.

On 11/22/05, ako... <removed_email_address@domain.invalid> wrote:
> > @attributes << a3
>
> this is something i have never seen. would you explain the 'def' line
> above? is this the same as class << @attributes; def << ...; end ?
>
>
>


--
"Remember. Understand. Believe. Yield! -> http://ruby-lang.org"

Jeff W.
jeff.darklight (Guest)
on 2005-11-23 03:26
(Received via mailing list)
I would do

a = Hash.new { || [] }

def a.addValue( valueHash )
  valueHash.each_pair { |key,value| self[ key ] <<= value }
end

a.addValue "blah" => "a"
a.addValue "blah" => "b"
a.addValue "blah" => "c"

I kinda like the look of the arrows ;)

j.

--
"Remember. Understand. Believe. Yield! -> http://ruby-lang.org"

Jeff W.
joevandyk (Guest)
on 2005-11-23 03:34
(Received via mailing list)
On 11/22/05, ako... <removed_email_address@domain.invalid> wrote:
> hello,
>
> i am still learning.

Hopefully there isn't anyone who isn't!
dblack (Guest)
on 2005-11-23 03:38
(Received via mailing list)
Hi --

On Wed, 23 Nov 2005, Jeff W. wrote:

> I would do
>
> a = Hash.new { || [] }

I believe that's the first empty || I've ever seen.  It's awfully
confusing (my first reaction was: *what* or an empty array? :-)  I'd
strongly encourage you to eschew that construct.  It's deservedly
unheard of :-)


David
ara.t.howard (Guest)
on 2005-11-23 03:50
(Received via mailing list)
On Wed, 23 Nov 2005, David A. Black wrote:

> strongly encourage you to eschew that construct.  It's deservedly
> unheard of :-)

i must confess i love it!  probably won't use it much.  but i love it.

-a
jeff.darklight (Guest)
on 2005-11-23 03:54
(Received via mailing list)
ok ...

a = Hash.new ->{ [] }

# new syntax ;)

...

On 11/22/05, Ara.T.Howard <removed_email_address@domain.invalid> wrote:
> >
> ===============================================================================
> | ara [dot] t [dot] howard [at] gmail [dot] com
> | all happiness comes from the desire for others to be happy.  all misery
> | comes from the desire for oneself to be happy.
> | -- bodhicaryavatara
>
> ===============================================================================
>
>
>


--
"Remember. Understand. Believe. Yield! -> http://ruby-lang.org"

Jeff W.
james_b (Guest)
on 2005-11-23 03:58
(Received via mailing list)
Ara.T.Howard wrote:
>>
>> I believe that's the first empty || I've ever seen.  It's awfully
>> confusing (my first reaction was: *what* or an empty array? :-)  I'd
>> strongly encourage you to eschew that construct.  It's deservedly
>> unheard of :-)
>
>
> i must confess i love it!  probably won't use it much.  but i love it.

I love it too, and will use it simply because David said he'd never seen
it before.



James

--

http://www.ruby-doc.org       - Ruby Help & Documentation
http://www.artima.com/rubycs/ - Ruby Code & Style: Writers wanted
http://www.rubystuff.com      - The Ruby Store for Ruby Stuff
http://www.jamesbritt.com     - Playing with Better Toys
http://www.30secondrule.com   - Building Better Tools
dblack (Guest)
on 2005-11-23 04:06
(Received via mailing list)
Hi --

On Wed, 23 Nov 2005, Ara.T.Howard wrote:

>> I believe that's the first empty || I've ever seen.  It's awfully
>> confusing (my first reaction was: *what* or an empty array? :-)  I'd
>> strongly encourage you to eschew that construct.  It's deservedly
>> unheard of :-)
>
> i must confess i love it!  probably won't use it much.  but i love it.

Keep it firmly in mind if there's every another obfuscated Ruby
contest.... :-)


David
dblack (Guest)
on 2005-11-23 04:10
(Received via mailing list)
Hi --

On Wed, 23 Nov 2005, James B. wrote:

>>>
> before.
But now I've seen it, so you don't have to :-)


David
leavengood (Guest)
on 2005-11-23 04:18
(Received via mailing list)
On 11/22/05, Ara.T.Howard <removed_email_address@domain.invalid> wrote:
> > I believe that's the first empty || I've ever seen.  It's awfully
> > confusing (my first reaction was: *what* or an empty array? :-)  I'd
> > strongly encourage you to eschew that construct.  It's deservedly
> > unheard of :-)
>
> i must confess i love it!  probably won't use it much.  but i love it.

Yeah that is nuts...but I really like it :)

Ryan
dblack (Guest)
on 2005-11-23 04:30
(Received via mailing list)
Hi --

On Wed, 23 Nov 2005, Ryan L. wrote:

>>>
>>> I believe that's the first empty || I've ever seen.  It's awfully
>>> confusing (my first reaction was: *what* or an empty array? :-)  I'd
>>> strongly encourage you to eschew that construct.  It's deservedly
>>> unheard of :-)
>>
>> i must confess i love it!  probably won't use it much.  but i love it.
>
> Yeah that is nuts...but I really like it :)

Et tu, Leavengood? :-)


David
leavengood (Guest)
on 2005-11-23 04:42
(Received via mailing list)
On 11/22/05, David A. Black <removed_email_address@domain.invalid> wrote:
>
> Et tu, Leavengood? :-)

ROFL. Yes indeed. I have yet to really reveal it, but I have quite a
penchant for obfuscated Ruby code, and plan to compete in the next
IORCC. I also enjoy Ruby Golf, as can be seen in my recent Ruby Q.
submission.

I just like the irony that it takes a really good Ruby programmer to
write such bad, evil code :)

Ryan
rascal1182 (Guest)
on 2005-11-23 04:46
(Received via mailing list)
On 11/22/05, David A. Black <removed_email_address@domain.invalid> wrote:
> On Wed, 23 Nov 2005, Jeff W. wrote:
>
> > I would do
> >
> > a = Hash.new { || [] }
>
> I believe that's the first empty || I've ever seen.  It's awfully
> confusing (my first reaction was: *what* or an empty array? :-)  I'd
> strongly encourage you to eschew that construct.  It's deservedly
> unheard of :-)

Perhaps I'm missing something.  Is there something wrong with the
following?

a = Hash.new { [] }

irb tells me that it gets a new array each time.
lyndon.samson (Guest)
on 2005-11-23 05:10
(Received via mailing list)
It would be nice if there was a wiki page somewhere of these
Uberdioms...
dblack (Guest)
on 2005-11-23 05:26
(Received via mailing list)
Hi --

On Wed, 23 Nov 2005, Lyndon S. wrote:

> It would be nice if there was a wiki page somewhere of these Uberdioms...

I'm not sure what you mean.  A wiki page of... ?


David
leavengood (Guest)
on 2005-11-23 05:30
(Received via mailing list)
On 11/22/05, Rob R. <removed_email_address@domain.invalid> wrote:
>
> Perhaps I'm missing something.  Is there something wrong with the following?
>
> a = Hash.new { [] }
>
> irb tells me that it gets a new array each time.

No that is how it works and that is basically what Jeff's code does.
He just has empty "goal-posts" in the block as well (it isn't really
an or operation.) He gets around the new array every time thing by
using self[key] <<= value, which is self[key] = self[key] << value.
The block will only be called when there is no values for the given
key, and once the above code is called, there will be a value for the
given key (the array.) It is pretty slick (I didn't even know <<=
existed.)

Ryan
james_b (Guest)
on 2005-11-23 06:43
(Received via mailing list)
Lyndon S. wrote:
> It would be nice if there was a wiki page somewhere of these Uberdioms...

Such as http://www.rubygarden.org/ruby?RubyIdioms ?

James
lyndon.samson (Guest)
on 2005-11-23 06:47
(Received via mailing list)
On 11/23/05, David A. Black <removed_email_address@domain.invalid> wrote:
>
> Hi --
>
> On Wed, 23 Nov 2005, Lyndon S. wrote:
>
> > It would be nice if there was a wiki page somewhere of these
> Uberdioms...
>
> I'm not sure what you mean.  A wiki page of... ?


Sorry :-)

Uberdioms = Uber Idioms = Made up word representing powerfull and
sometimes
lacking in immediate clarity language constructs that programmers should
be aware of but not necessarily utilising in all circumstances.





David
vjoel (Guest)
on 2005-11-23 06:59
(Received via mailing list)
David A. Black wrote:
> confusing (my first reaction was: *what* or an empty array? :-)  I'd
> strongly encourage you to eschew that construct.  It's deservedly
> unheard of :-)

It's not completely useless:

irb(main):001:0> noargs = proc { || 3 }
=> #<Proc:0xb7b3558c@(irb):1>
irb(main):002:0> noargs[]
=> 3
irb(main):003:0> noargs[2]
ArgumentError: wrong number of arguments (1 for 0)
        from (irb):3
        from (irb):3
lyndon.samson (Guest)
on 2005-11-23 07:11
(Received via mailing list)
Nice RaDD work ( Rapid Documentation Development ) !
jeff.darklight (Guest)
on 2005-11-23 10:36
(Received via mailing list)
Heh, and to think the only reason I did it was because I figured just
having
the { [] } would confuse things ( badly formed hash declaration ) so I
put
the goalposts in just to be sure that it saw things as a block body ...

I'll gladly take credit, I'm glad I'll be remembered for something now (
heh, need to get that into the rubyscore app )... for my "empty
goalpost"
strategem ;) . I'm not Dave T. or DHH or _why ... or matz ... or any
of
the countless others that have helped me better myself as a Rubyist, but
hopefully one day I'll get to have a big impact ... and pay them all
back. I
thank you all everyday I get to play with Ruby.

Anyways, You could seperate them if you didn't want them to look like or
...
like ...

{ | | [] } ... although that's kinda ugly to me.

I'd be just as happy to use the new block syntax ->{ [] } ... when is
that
going to see the light of day ???

j.

--
"Remember. Understand. Believe. Yield! -> http://ruby-lang.org"

Jeff W.
mfp (Guest)
on 2005-11-23 10:40
(Received via mailing list)
On Wed, Nov 23, 2005 at 01:58:01PM +0900, Joel VanderWerf wrote:
> It's not completely useless:
>
> irb(main):001:0> noargs = proc { || 3 }
> => #<Proc:0xb7b3558c@(irb):1>
> irb(main):002:0> noargs[]
> => 3
> irb(main):003:0> noargs[2]
> ArgumentError: wrong number of arguments (1 for 0)
>         from (irb):3
>         from (irb):3

Maybe not for long

[lambda{ }.arity, RUBY_VERSION] # => [0, "1.9.0"]

vs.

[lambda{ }.arity, RUBY_VERSION] # => [-1, "1.8.3"]
christophe.grandsire (Guest)
on 2005-11-23 14:44
(Received via mailing list)
Selon "ako..." <removed_email_address@domain.invalid>:

>
> this is something i have never seen. would you explain the 'def' line
> above? is this the same as class << @attributes; def << ...; end ?
>

If I understand correctly you are asking whether:

def @attributes.<<(obj)
  ...
end

is the same as:

class << @attributes
  def <<(obj)
    ...
  end
end

(I rewrote them because the clash of << as syntax and << as method made
it a bit
difficult to read).

The short answer is "yes". The long asnwer is that both are ways to add
a
singleton method to a particular object, @attributes in this case. The
first
one is just shorter and practical when you want to create just one
singleton
method. But it's mostly a matter of style.
--
Christophe G..

http://rainbow.conlang.free.fr

It takes a straight mind to create a twisted conlang.
dblack (Guest)
on 2005-11-23 15:45
(Received via mailing list)
Hi --

On Wed, 23 Nov 2005, Joel VanderWerf wrote:

>> I believe that's the first empty || I've ever seen.  It's awfully
> irb(main):003:0> noargs[2]
> ArgumentError: wrong number of arguments (1 for 0)
>        from (irb):3
>        from (irb):3

Interesting.  I wonder why.  And it's yet another case where
proc/lambda and Proc.new are different:

   noargs = Proc.new { || 3 }
   => #<Proc:0x0033654c@(irb):8>
   irb(main):009:0> noargs[2]
   => 3

It seems very fragile to me as a way of communicating what's going on.
There are two ways of saying "This takes no arguments", and what they
mean depends on the Proc/proc distinction.  I guess this is old news
-- it's just another twist, and one I hadn't noticed before, on that
whole area.

(Matz, please proceed with the removal of 'proc' :-)


David
dblack (Guest)
on 2005-11-23 15:49
(Received via mailing list)
Hi --

On Wed, 23 Nov 2005, Jeff W. wrote:

>
> Anyways, You could seperate them if you didn't want them to look like or ...
> like ...
>
> { | | [] } ... although that's kinda ugly to me.

No argument there :-)

> I'd be just as happy to use the new block syntax ->{ [] } ... when is that
> going to see the light of day ???

I think I'm not alone is saying: hopefully never :-)  Anyway, you can
just do:

   Hash.new { [] }

It's a pretty common idiom, and the block is unambiguously a block.
(If it were a hash argument it would have to be in parentheses.)


David
dblack (Guest)
on 2005-11-23 16:01
(Received via mailing list)
Hi --

On Wed, 23 Nov 2005, Christophe G. wrote:

>>> @attributes << a2
> end
> difficult to read).
>
> The short answer is "yes". The long asnwer is that both are ways to add a
> singleton method to a particular object, @attributes in this case. The first
> one is just shorter and practical when you want to create just one singleton
> method. But it's mostly a matter of style.

There's also a (usually not too important) difference involving the
scope of constants.  The << version will see constants in the
singleton class, whereas the def obj.meth version won't:

   obj = Object.new

   A = 1

   class << obj
     A = 2
     def x
       puts A
     end
   end

   def obj.y
     puts A
   end

   obj.x         # 2
   obj.y         # 1


David
bob.news (Guest)
on 2005-11-23 16:21
(Received via mailing list)
David A. Black wrote:
>> now ( heh, need to get that into the rubyscore app )... for my
>
> It's a pretty common idiom, and the block is unambiguously a block.
> (If it were a hash argument it would have to be in parentheses.)

Note though that this idiom will most likely lead to surprising results
wrt the OP's requirement. :-)

Cheers

    robert
gavin (Guest)
on 2005-11-23 17:22
(Received via mailing list)
On Nov 22, 2005, at 5:45 PM, Bill K. wrote:
> @attributes = Hash.new {|h,k| h[k] = Array.new}

Hey, thanks for that! I had no idea that the block form of Hash
creation had block arguments. Sure it's in 'ri', but who looks there? ;)

I often see people suggesting:
Hash.new{ [] }
without realizing that this doesn't set the value on the hash, just
returns a blank array. I've never been able to use the block
constructor syntax because it was so useless (because I also didn't
know that <<= was a valid compound method).

foo = Hash.new{ [] }
foo[:bar] << 1
foo[:foo] << 2
foo[:bar] << 3
p foo
#=>{}

foo = Hash.new{ |h,v| h[v]=[] }
foo[:bar] << 1
foo[:foo] << 2
foo[:bar] << 3
p foo
#=>{:bar=>[1, 3], :foo=>[2]}

foo = Hash.new{ [] }
foo[:bar] <<= 1
foo[:foo] <<= 2
foo[:bar] <<= 3
p foo
#=>{:bar=>[1, 3], :foo=>[2]}
This topic is locked and can not be replied to.