[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Array.sort problem

Larme

4/21/2007 6:17:00 PM

Dear all, I'm a newbie to ruby and today when I'm writing a simple
script to process some data, I found something I can't understand.

The data is stored in several column seperated by tab or space. I use
the following code to get the data (assuming the data comes from
standard input and all numbers are integer)

data=[]
counter = 0
while line = STDIN.gets
data[counter] = line.split
data[counter].map! {|str| str.to_i}
counter += 1
end

hence data[i] is an array hold all the numbers in the ith line, data[i]
[j] is the number on ith line and jth column. Then what I want the
script to do is sorting lines according to a specified column. I
thought the following code should work:

result = data.sort {|x, y| x[col] <=> y[col] }

where the col determine which column the script will sort according
to. However ruby raise a error saying:
"undefined method `<=>' for nil:NilClass (NoMethodError)
from ana.rb:16:in `sort'
from ana.rb:16
"

I have to write the code as

result = data.sort {|x, y| x[col].to_i <=> y[col].to_i }

to let the script run properly. I'm quite confused here. I think the
elements of array data are converted to integer when the code

data[counter].map! {|str| str.to_i}

finished. However why ruby still requires a explicit conversion when I
use the data.sort?

7 Answers

hemant

4/21/2007 6:50:00 PM

0

On 4/21/07, Larme <lalalarme@gmail.com> wrote:
> Dear all, I'm a newbie to ruby and today when I'm writing a simple
> script to process some data, I found something I can't understand.
>
> The data is stored in several column seperated by tab or space. I use
> the following code to get the data (assuming the data comes from
> standard input and all numbers are integer)
>
> data=[]
> counter = 0
> while line = STDIN.gets
> data[counter] = line.split
> data[counter].map! {|str| str.to_i}
> counter += 1
> end
>
> hence data[i] is an array hold all the numbers in the ith line, data[i]
> [j] is the number on ith line and jth column. Then what I want the
> script to do is sorting lines according to a specified column. I
> thought the following code should work:
>
> result = data.sort {|x, y| x[col] <=> y[col] }
>
> where the col determine which column the script will sort according
> to. However ruby raise a error saying:
> "undefined method `<=>' for nil:NilClass (NoMethodError)
> from ana.rb:16:in `sort'
> from ana.rb:16
> "
>
> I have to write the code as
>
> result = data.sort {|x, y| x[col].to_i <=> y[col].to_i }
>
> to let the script run properly. I'm quite confused here. I think the
> elements of array data are converted to integer when the code
>
> data[counter].map! {|str| str.to_i}
>
> finished. However why ruby still requires a explicit conversion when I
> use the data.sort?
>

Yes, they are. You might be doing some typo or other crap. Following
program runs verbatim:

data=[]
counter = 0
while line = STDIN.gets
data[counter] = line.split
data[counter].map! {|str| str.to_i}
counter += 1
end

#p data.sort_by { |x| x[2] } #=> you can use sort_by as an alternative

p data.sort {|x,y| x[2] <=> y[2] } #=> This also work.

Sebastian Hungerecker

4/21/2007 7:23:00 PM

0

Larme wrote:
> I have to write the code as
>
> result = data.sort {|x, y| x[col].to_i <=> y[col].to_i }
>
> to let the script run properly. I'm quite confused here. I think the
> elements of array data are converted to integer when the code
>
> data[counter].map! {|str| str.to_i}
>
> finished. However why ruby still requires a explicit conversion when I
> use the data.sort?

If you have an array arr with n elements which you all turn into integers,
arr[i] with i>=n will still be nil. So if in your case not all rows have more
than col columns, that would explain the problem.


HTH,
Sebastian Hungerecker
--
NP: Kataklysm - Where the Enemy Sleeps...
Ist so, weil ist so
Bleibt so, weil war so

Robert Klemme

4/21/2007 7:26:00 PM

0

On 21.04.2007 20:16, Larme wrote:
> Dear all, I'm a newbie to ruby and today when I'm writing a simple
> script to process some data, I found something I can't understand.
>
> The data is stored in several column seperated by tab or space. I use
> the following code to get the data (assuming the data comes from
> standard input and all numbers are integer)
>
> data=[]
> counter = 0
> while line = STDIN.gets
> data[counter] = line.split
> data[counter].map! {|str| str.to_i}
> counter += 1
> end
>
> hence data[i] is an array hold all the numbers in the ith line, data[i]
> [j] is the number on ith line and jth column. Then what I want the
> script to do is sorting lines according to a specified column. I
> thought the following code should work:
>
> result = data.sort {|x, y| x[col] <=> y[col] }
>
> where the col determine which column the script will sort according
> to. However ruby raise a error saying:
> "undefined method `<=>' for nil:NilClass (NoMethodError)
> from ana.rb:16:in `sort'
> from ana.rb:16
> "
>
> I have to write the code as
>
> result = data.sort {|x, y| x[col].to_i <=> y[col].to_i }
>
> to let the script run properly. I'm quite confused here. I think the
> elements of array data are converted to integer when the code
>
> data[counter].map! {|str| str.to_i}
>
> finished. However why ruby still requires a explicit conversion when I
> use the data.sort?

You probably have lines with differing number of entries and thus
sometimes x[col] just returns nil.

You could do something like:

data.sort_by {|x| x[col].to_i}
data.sort_by {|x| x[col] || 0}

If you want to be sure that you extract only integers you could do

l.scan(/\d+/).map {|x| x.to_i}

instead of the split.

Lots of options...

Kind regards

robert


Larme

4/21/2007 7:39:00 PM

0

On Apr 22, 3:25 am, Robert Klemme <shortcut...@googlemail.com> wrote:
> On 21.04.2007 20:16, Larme wrote:
>
>
>
> > Dear all, I'm a newbie to ruby and today when I'm writing a simple
> > script to process some data, I found something I can't understand.
>
> > The data is stored in several column seperated by tab or space. I use
> > the following code to get the data (assuming the data comes from
> > standard input and all numbers are integer)
>
> > data=[]
> > counter = 0
> > while line = STDIN.gets
> > data[counter] = line.split
> > data[counter].map! {|str| str.to_i}
> > counter += 1
> > end
>
> > hence data[i] is an array hold all the numbers in the ith line, data[i]
> > [j] is the number on ith line and jth column. Then what I want the
> > script to do is sorting lines according to a specified column. I
> > thought the following code should work:
>
> > result = data.sort {|x, y| x[col] <=> y[col] }
>
> > where the col determine which column the script will sort according
> > to. However ruby raise a error saying:
> > "undefined method `<=>' for nil:NilClass (NoMethodError)
> > from ana.rb:16:in `sort'
> > from ana.rb:16
> > "
>
> > I have to write the code as
>
> > result = data.sort {|x, y| x[col].to_i <=> y[col].to_i }
>
> > to let the script run properly. I'm quite confused here. I think the
> > elements of array data are converted to integer when the code
>
> > data[counter].map! {|str| str.to_i}
>
> > finished. However why ruby still requires a explicit conversion when I
> > use the data.sort?
>
> You probably have lines with differing number of entries and thus
> sometimes x[col] just returns nil.
>
> You could do something like:
>
> data.sort_by {|x| x[col].to_i}
> data.sort_by {|x| x[col] || 0}
>
> If you want to be sure that you extract only integers you could do
>
> l.scan(/\d+/).map {|x| x.to_i}
>
> instead of the split.
>
> Lots of options...
>
> Kind regards
>
> robert


Thank all of you. Yes, the problem is that the column number is not
fixed -- it should be, but my friend who prepare the data made some
thing wrong.

Ari Brown

4/21/2007 11:22:00 PM

0


On Apr 21, 2007, at 2:20 PM, Larme wrote:
<snip>
> 1
> 2 data=[]
> 3 counter = 0
> 4 while line = STDIN.gets
> 5 data[counter] = line.split
> 6 data[counter].map! {|str| str.to_i}
> 7 counter += 1
> 8 end

Ok, so I'm a noob trying to learn something here...

Shouldn't line 4 be presented with a double = (==) since you're
trying do something while line == STDIN.gets?

Also, does STDIN.gets need to be stated in a previous line? Or will
it be prompted from within the 'while' statement.

<snip>
--------------------------------------------|
If you're not living on the edge,
then you're just wasting space.



Philip M. Gollucci

4/22/2007 12:17:00 AM

0

>> 4 while line = STDIN.gets

> Ok, so I'm a noob trying to learn something here...
>
> Shouldn't line 4 be presented with a double = (==) since you're trying
> do something while line == STDIN.gets?
No, the assignment of line = STDIN.gets happens first which reads up to
a '\n' including it. While then loops while this value is true.

When there is no more inmput, line will be assigned nothing which is
false and the loop ends.

This works identically to other languages like perl/python/php


--
------------------------------------------------------------------------
Philip M. Gollucci (pgollucci@p6m7g8.com) 323.219.4708
Consultant / http://p6m7g8.net/Resume/re...
Senior Software Engineer - TicketMaster - http://ticket...
1024D/EC88A0BF 0DE5 C55C 6BF3 B235 2DAB B89E 1324 9B4F EC88 A0BF

Work like you don't need the money,
love like you'll never get hurt,
and dance like nobody's watching.

Ari Brown

4/22/2007 2:41:00 PM

0


On Apr 21, 2007, at 8:16 PM, Philip M. Gollucci wrote:

>>> 4 while line = STDIN.gets

<snip>

> No, the assignment of line = STDIN.gets happens first which reads
> up to a '\n' including it. While then loops while this value is true.

Oh, so it's not checking whether line == STDIN.gets (immediately),
but rather assigning STDIN.gets to line, and then checking whether
that's true?

Nice, I learned something!

---------------------------------------------------------------|
~Ari
"I don't suffer from insanity. I enjoy every minute of it" --1337est
man alive