Some questions on language syntax


#1

Hi, I’m new to this language and as I’m Perl user, some things seems
strange to me:

= %w{a b} produces [‘a’, ‘b’]. Is there some similarily easy way for
{‘a’ => ‘b’}? Or, can I transform an array to some “list”? I can use
Hash[‘a’, ‘b’], but not Hash[%w{…}], because I cannot generate a list,
only an array.

= how can I do ‘perlish’ a[1] <=> b[1] || a[2] <=> b[2] if I want
compare a and b accordind to some my own rules, i.e. if a[1] == b[2],
“return” a[2] <=> b[2]? In Ruby this is not possible, because 0 is true.

= can I somehow make ruby produce warnings on 1 == ‘1’ (number ==
string) like comparisons? In Perl true, in Ruby false. Many my mistakes
are of this kind and as these values seems same on output. :wink:

= why I can use {|…| …} as argument for map, each etc., but I cannot
write foo = {|…| …}, though I can write bar = […] or bar = {…}?

Thanks,

P.


#2

Pavel S. scribbled on Tuesday 14 Mar 2006 21:50:

Hi, I’m new to this language and as I’m Perl user, some things seems
strange to me:

= %w{a b} produces [‘a’, ‘b’]. Is there some similarily easy way for
{‘a’ => ‘b’}? Or, can I transform an array to some “list”? I can use
Hash[‘a’, ‘b’], but not Hash[%w{…}], because I cannot generate a list,
only an array.

You can, however, expand the array:
Hash[*%w{a b c d}] yields {“a”=>“b”, “c”=>“d”}

= how can I do ‘perlish’ a[1] <=> b[1] || a[2] <=> b[2] if I want
compare a and b accordind to some my own rules, i.e. if a[1] == b[2],
“return” a[2] <=> b[2]? In Ruby this is not possible, because 0 is true.

irb(main):006:0> 0 == true
=> false

0 is not true :slight_smile:

= can I somehow make ruby produce warnings on 1 == ‘1’ (number ==
string) like comparisons? In Perl true, in Ruby false. Many my mistakes
are of this kind and as these values seems same on output. :wink:

Not that I know of. Well, you could extend the == operator on Fixnum
(and
String) to throw a warning:

class Fixnum
def ==(a)
warn “Warn” unless a.is_a? Fixnum
super(a)
end
end

= why I can use {|…| …} as argument for map, each etc., but I cannot
write foo = {|…| …}, though I can write bar = […] or bar = {…}?

You can’t use {} literals in an assignment to denote a block because
Ruby
thinks it is supposed to be a Hash. Use Kernel#proc (or the alias
#lambda)
for that:

irb(main):026:0> p = proc {|n| puts n}
=> #Proc:0xb7c98138@:26(irb)
irb(main):027:0> p.call(5)
5

You can pass that block to any method that wants a block (note the &
operator that denotes the passed argument is a block):

irb(main):029:0> [33, 44, 55].each &p
33
44
55

See also Method#block_given?

Hope that helps.


#3

On Mar 14, 2006, at 3:03 PM, Pavel S. wrote:

Hi, I’m new to this language and as I’m Perl user, some things
seems strange to me:

= %w{a b} produces [‘a’, ‘b’]. Is there some similarily easy way
for {‘a’ => ‘b’}? Or, can I transform an array to some “list”? I
can use Hash[‘a’, ‘b’], but not Hash[%w{…}], because I cannot
generate a list, only an array.

You are looking for the “splat” operator:

Hash[*%w{a b}]
=> {“a”=>“b”}

= how can I do ‘perlish’ a[1] <=> b[1] || a[2] <=> b[2] if I want
compare a and b accordind to some my own rules, i.e. if a[1] == b
[2], “return” a[2] <=> b[2]? In Ruby this is not possible, because
0 is true.

We use sort_by() for that:

%w{one two three}.sort_by { |str| [-str.length, str] }
=> [“three”, “one”, “two”]

= can I somehow make ruby produce warnings on 1 == ‘1’ (number ==
string) like comparisons? In Perl true, in Ruby false. Many my
mistakes are of this kind and as these values seems same on
output. :wink:

Hmm, you could redefine ==(), but you don’t want to do that, trust
me. :wink: The transition phase will pass in time…

= why I can use {|…| …} as argument for map, each etc., but I
cannot write foo = {|…| …}, though I can write bar = […] or
bar = {…}?

You can use lambda() for this:

proc_object = lambda { |…| … }

James Edward G. II


#4

Pavel S. wrote:

“return” a[2] <=> b[2]? In Ruby this is not possible, because 0 is true.

use #sort_by like:
Enumerable#sort_by { |obj| obj.fld1, obj.fld2 }

this list give good, quick, accurate answers, no?


#5

On Mar 14, 2006, at 3:03 PM, Pavel S. wrote:

= how can I do ‘perlish’ a[1] <=> b[1] || a[2] <=> b[2] if I want
compare a and b accordind to some my own rules, i.e. if a[1] == b
[2], “return” a[2] <=> b[2]? In Ruby this is not possible, because
0 is true.

James G. wrote:

We use sort_by() for that:

Or nonzero? … eg.

(a[1] <=> b[2]).nonzero? || (a[2] <=> b[2])


– Jim W.


#6

On Wed, 15 Mar 2006, Pavel S. wrote:

= how can I do ‘perlish’ a[1] <=> b[1] || a[2] <=> b[2] if I want compare a
and b accordind to some my own rules, i.e. if a[1] == b[2], “return” a[2] <=>
b[2]? In Ruby this is not possible, because 0 is true.

because in ruby you don’t have too:

a <=> b

when a and b are arrays just does that. if you wanted to compare only
the
first elements (assuming there are more) you can simply

a[0,2] <=> b[0,2]

or, if you a glutten for perlishment

[a[1], a[2]] <=> [b[0], b[1]]

you can do really compact sorting routines in ruby. i wrote one
yesterday
that sorts strings like this

/dmsp/nrt/data/incoming/afwa/2006.f13_0731556_DT.DAT
/dmsp/nrt/data/incoming/afwa/2006.f13_0731737_DS.DAT

where

2006.f13_0731556_DT.DAT
^^^^ ^^^ ^^^^^^^ ^^
| | | |
year sat time type

first by sat, then by year, then by time and finally by type

using only

pats = %w[ f\d\d ^\d{4} _\d{7} _\w{2} ].map{|p|/#{p}/}

basenames.sort!{|a,b| pats.map{|pat| a[pat]} <=> pats.map{|pat|
b[pat]} }

gotta love that!!

cheers.

-a


#7

On Wed, Mar 15, 2006 at 07:23:46AM +0900, Pavel S. wrote:

However, Jim W.'s (a[1] <=> b[2]).nonzero? || a[2] <=> b[2] seems OK

I don’t think that actually does what you want. The test should
return -1 if a[1] is less than b[2], but instead it will return
“true”.


#8

Bernhard ‘elven’ Stoeckner wrote:

Pavel S. scribbled on Tuesday 14 Mar 2006 21:50:

= %w{a b} produces [‘a’, ‘b’]. Is there some similarily easy way for
{‘a’ => ‘b’}? Or, can I transform an array to some “list”? I can use
Hash[‘a’, ‘b’], but not Hash[%w{…}], because I cannot generate a list,
only an array.

You can, however, expand the array:
Hash[*%w{a b c d}] yields {“a”=>“b”, “c”=>“d”}

Oh, that’s great!!! How could I not notice that? :wink:

= how can I do ‘perlish’ a[1] <=> b[1] || a[2] <=> b[2] if I want
compare a and b accordind to some my own rules, i.e. if a[1] == b[2],
“return” a[2] <=> b[2]? In Ruby this is not possible, because 0 is true.

irb(main):006:0> 0 == true
=> false

0 is not true :slight_smile:

Well, to be more precise, 0 is not equal to false (as is in Perl). :slight_smile:

So, how do you do a[1] <=> b[1] || a[2] <=> b[2]? Or, may be a.x <=> b.y
|| a.w <=> b.z would be better — I don’t want to suppose anything
about the internal structure of a and b now. However, Jim W.'s
(a[1] <=> b[2]).nonzero? || a[2] <=> b[2] seems OK (and it’s even in
RDoc for Numeric#nonzero? ;-).

Gene T. wrote:

this list give good, quick, accurate answers, no?

:wink: Must agree with this. Thank for all suggestions, they are very
valuable for me.

P.


#9

Edward F. wrote:

On Wed, Mar 15, 2006 at 07:23:46AM +0900, Pavel S. wrote:

However, Jim W.'s (a[1] <=> b[2]).nonzero? || a[2] <=> b[2] seems OK

I don’t think that actually does what you want. The test should
return -1 if a[1] is less than b[2], but instead it will return
“true”.

No, it works:

(0 <=> 1).nonzero?
=> -1

It was for this exact purpose that nonzero? was introduced.

BTW, I hope no one was confused by the typo … the first b[2] should
have been a b[1].

– Jim W.


#10

removed_email_address@domain.invalid wrote:

year sat time type

first by sat, then by year, then by time and finally by type

using only

pats = %w[ f\d\d ^\d{4} _\d{7} _\w{2} ].map{|p|/#{p}/}

basenames.sort!{|a,b| pats.map{|pat| a[pat]} <=> pats.map{|pat| b[pat]} }

Interesting idea, but may be _\w{2}. would be more appropriate instead
of _\w{2} which can match also against a beginnig of the ‘time’ part. :slight_smile:

P.


#11

On 14-Mar-06, at 5:28 PM, Edward F. wrote:

On Wed, Mar 15, 2006 at 07:23:46AM +0900, Pavel S. wrote:

However, Jim W.'s (a[1] <=> b[2]).nonzero? || a[2] <=> b[2]
seems OK

I don’t think that actually does what you want. The test should
return -1 if a[1] is less than b[2], but instead it will return
“true”.

Are you sure?
------------------------------------------------------- Numeric#nonzero?
num.nonzero? => num or nil

  Returns _num_ if _num_ is not zero, +nil+ otherwise. This behavior
  is useful when chaining comparisons:

     a = %w( z Bb bB bb BB a aA Aa AA A )
     b = a.sort {|a,b| (a.downcase <=> b.downcase).nonzero? || a

<=> b }
b #=> [“A”, “a”, “AA”, “Aa”, “aA”, “BB”, “Bb”, “bB”, “bb”,
“z”]

Mike

Mike S. removed_email_address@domain.invalid
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.


#12

On Wed, 15 Mar 2006, Pavel S. wrote:

| | | |
Interesting idea, but may be _\w{2}. would be more appropriate instead of
_\w{2} which can match also against a beginnig of the ‘time’ part. :slight_smile:

P.

right you are! bug number 63 squashed.

thanks!

-a


#13

On Wed, 15 Mar 2006, Mike S. wrote:

sorted_basenames = basenames.sort_by { |name| name.unpack(‘x5 A3 X8 A4 x5 A7
x A2’) }

This is just an excuse to expose unpack and sort_by to people, not a
suggestion that it’s necessarily appropriate or better in this case.

i actually like that. whether regexes or pack codes are more obtuse is
definitely debatable - but that’s pretty clean looking

thanks for the tip.

-a


#14

On 14-Mar-06, at 5:03 PM, removed_email_address@domain.invalid wrote:

^^^^ ^^^ ^^^^^^^ ^^
[pat]} }

gotta love that!!

Tangentially speaking you can use unpack and sort_by to do this kind
of thing if it suits the situation (admittedly there’s not a
sort_by!, but let’s not let that get in the way :slight_smile:

sorted_basenames = basenames.sort_by { |name|
name.unpack(‘A4 x A3 x A7 x A2’).values_at(1, 0, 2, 3)
}

or the delightful

sorted_basenames = basenames.sort_by { |name| name.unpack(‘x5 A3 X8
A4 x5 A7 x A2’) }

This is just an excuse to expose unpack and sort_by to people, not a
suggestion that it’s necessarily appropriate or better in this case.

Mike

Mike S. removed_email_address@domain.invalid
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.