some questions on language syntax

P

Pavel Smerk

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. ;-)

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

Thanks,

P.
 
B

Bernhard 'elven' Stoeckner

Pavel Smerk 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 :)
= 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. ;-)

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@(irb):26>
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.
 
J

James Edward Gray II

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:
=> {"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. ;-)

Hmm, you could redefine ==(), but you don't want to do that, trust
me. ;) 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 Gray II
 
G

Gene Tani

Pavel said:
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.

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

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

Jim Weirich

= 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 said:
We use sort_by() for that:

Or nonzero? ... eg.

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

ara.t.howard

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

Pavel Smerk

Bernhard said:
Pavel Smerk 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? ;-)
= 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 :)

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

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 Weirich's
(a[1] <=> b[2]).nonzero? || a[2] <=> b[2] seems OK (and it's even in
RDoc for Numeric#nonzero? ;-).

Gene said:
this list give good, quick, *accurate* answers, no?

;-) Must agree with this. Thank for all suggestions, they are very
valuable for me.

P.
 
E

Edward Faulkner

--rS8CxjVDS/+yyDmU
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

However, Jim Weirich'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".


--rS8CxjVDS/+yyDmU
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFEF0NWnhUz11p9MSARArnlAJsEynbW9tjVxxnSzJEcvLR2EbdqTQCg29ov
Q91xjuoEzIiq49+LHKjUSwo=
=of11
-----END PGP SIGNATURE-----

--rS8CxjVDS/+yyDmU--
 
P

Pavel Smerk

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

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. :)

P.
 
M

Mike Stok

However, Jim Weirich'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 Stok <[email protected]>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.
 
J

Jim Weirich

Edward said:
However, Jim Weirich'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 Weirich
 
A

ara.t.howard

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

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. :)

P.

right you are! bug number 63 squashed.

thanks!

-a
 
M

Mike Stok

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

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

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 Stok <[email protected]>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.
 
A

ara.t.howard

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

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.

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,202
Messages
2,571,057
Members
47,667
Latest member
DaniloB294

Latest Threads

Top