New to Ruby - pls help in translating this

Am Freitag, 9. Dezember 2005 21:31 schrieb Logan C.:

Well, if it was a string. The problem is fixnums are immediate
values. ++ would therefore be an operation on the variable a, rather
than the object that a points at.

well, there is a+=1
and a++ would be a+! imho…

Quoting James Edward G. II [email protected]:

Replacing the above with:

ARGF.each do |line|

Is the same thing, but more powerful. You could feed it multiple
files at once, or use it in pipelined processing. Just FYI.

Ah, thank you. I couldn’t remember how to do that. That’s closer
in spirit to his original Perl fragment, which used <>.

Perl:

while (<>) {

}

Ruby:

while ARGF.gets

end

(not that I’m advocating $_)

-mental

Sam Dela C. [email protected] wrote:

I’m starting to use Ruby in one of my projects at work. I’m
coming from a Perl background.

In my project I would need to parse a list of numbers
(thousands of them) and then return the duplicates. In perl,
I can do this:

Perl code

%hash = {};

That doesn’t do what you think it does. In Perl, the {} here
will create a hash reference, which is a scalar datatype.
You’re assigning it to a %hash variable, which accepts LIST
data. This ends up being the same as:

%hash = ( {} );

Which creates a hash named %hash, stringifies the hash reference
and uses it as a key, and without any additional values to work
with, uses undef as a value for the key.

To see this in action:

use Data::Dumper;
my %hash = {};
print Dumper( \%hash );

Compare to:

use Data::Dumper;
my %hash = ();
print Dumper( \%hash );

Yes. You want to use parentheses.

while (<>)
{
chomp;
$hash{$_}++;
}

foreach my $key (sort keys %hash)
{
print “$key: $hash{$key}\n” if ($hash{$key} > 1);
}

HTH,
Tim H.

On 12/9/05, Eric H. [email protected] wrote:

(there are probably still better ways of doing this though)

I’ll go with:

seen = {}

ARGF.each do |elem|
print elem if seen.include? elem
seen[elem] = true
end

And yes, this way is much better (I knew it would be but, it’s nice to
see just how much better):

require ‘benchmark’
n = 100

build a big array with lots of duplication

@nums = (1…1_000).to_a
(1…1_000).step(17) {|num| @nums.push(num) }

set up two versions of our rubylike version

the original perl-like version and the

final version

def as_ary
seen_ary = Array.new

@nums.each do |elem|
$stderr.print elem if seen_ary.include?(elem)
seen_ary.push(elem)
end
end

def as_hash
seen = Hash.new

@nums.each do |elem|
$stderr.print elem if seen.include?(elem)
seen[elem] = true
end
end

then benchmark them to see how they perform

Benchmark.bm(10) do |x|
x.report(“as Array”) {for i in 1…n; as_ary; end }
x.report(“as Hash”) {for i in 1…n; as_hash; end }
end

and the results are:

./print_dups.rb 2> /dev/null

user system total real

#as Array 12.690000 0.030000 12.720000 ( 13.940651)
#as Hash 0.230000 0.000000 0.230000 ( 0.613217)

Or, in keeping with the DRY and KISS principles I humbly submit the
lowly shell command, uniq, instead of Ruby at all:

$ uniq -d

e.g.

/tmp corey$ cat foo
1
1
2
3
3
4
/tmp corey$ uniq -d foo
1
3
/tmp corey$

Although, it was interesting to see the diversity of Ruby solutions.

Corey

On 12/9/05, Corey J. [email protected] wrote:

2
3
3
4
/tmp corey$ uniq -d foo
1
3
/tmp corey$

but it doesn’t always work:
pate@linux:~/scratch> cat nums
1
2
3
4
4
5
6
5
7
pate@linux:~/scratch> uniq -d files
uniq: files: No such file or directory
pate@linux:~/scratch> uniq -d nums
4
pate@linux:~/scratch>

you need to do:
pate@linux:~/scratch> sort -n nums | uniq -d
4
5

but if this is supposed to be part of a larger program, shell
is probably the wrong way to go about it.

Tim,

Sorry and yes you are right. This block of code came from a big program
I
have. I had to modify some stuff to simplify before sending this out to
the mailing list but forgot to change the bracket - { to parentheis - (.
Originally I was using a reference to a hash. So sorry for those who
got
confused. Thanks for pointing this out.

Sam

Tim H. [email protected]
12/09/2005 02:04 PM
Please respond to
[email protected]

To
[email protected] (ruby-talk ML)
cc

Subject
Re: new to Ruby - pls help in translating this
Classification

List-Owner: mailto:[email protected]
List-Help: mailto:[email protected]?body=help
List-Unsubscribe: mailto:[email protected]?body=unsubscribe

Sam Dela C. [email protected] wrote:

I’m starting to use Ruby in one of my projects at work. I’m
coming from a Perl background.

In my project I would need to parse a list of numbers
(thousands of them) and then return the duplicates. In perl,
I can do this:

Perl code

%hash = {};

That doesn’t do what you think it does. In Perl, the {} here
will create a hash reference, which is a scalar datatype.
You’re assigning it to a %hash variable, which accepts LIST
data. This ends up being the same as:

%hash = ( {} );

Which creates a hash named %hash, stringifies the hash reference
and uses it as a key, and without any additional values to work
with, uses undef as a value for the key.

To see this in action:

use Data::Dumper;
my %hash = {};
print Dumper( \%hash );

Compare to:

use Data::Dumper;
my %hash = ();
print Dumper( \%hash );

Yes. You want to use parentheses.

while (<>)
{
chomp;
$hash{$_}++;
}

foreach my $key (sort keys %hash)
{
print “$key: $hash{$key}\n” if ($hash{$key} > 1);
}

HTH,
Tim H.

On 12/9/05, Chad P. [email protected] wrote:

Why? Backticks are great.

Platform independence?

Granted I get away with a lot via MingGW, but if you want to code on
Linux / OS X and work for people who want the code to run on
Windows… well… platform independance is important

Though it does of course depend what you’re working on. :slight_smile:

On Sat, Dec 10, 2005 at 11:37:02AM +0900, Gregory B. wrote:

Though it does of course depend what you’re working on. :slight_smile:
Good point. Okay, you win.

. . . except when I’m writing unix administration scripts.


Chad P. [ CCD CopyWrite | http://ccd.apotheon.org ]

unix virus: If you’re using a unixlike OS, please forward
this to 20 others and erase your system partition.

On 12/10/05, Chad P. [email protected] wrote:

Good point. Okay, you win.

. . . except when I’m writing unix administration scripts.

Of COURSE! :slight_smile:
You can even port a lot of those straight to windows via MSys and MinGW.
(Or it’s ugly cousin Cygwin)

Eric H. wrote:

seen = {}

ARGF.each do |elem|
print elem if seen.include? elem
seen[elem] = true
end

seen = {}
while s = gets
print s if seen.key? s
seen[ s ] = nil
end

Or:

seen = Hash.new(0)
while s = gets
print s if ( seen[s] += 1 ) > 1
end

William J. wrote:

while s = gets
print s if seen.key? s
seen[ s ] = nil
end

Or:

seen = Hash.new(0)
while s = gets
print s if ( seen[s] += 1 ) > 1
end

seen, s = Hash.new(0)
print s if ( seen[s] += 1 ) > 1 while s = gets

On Sat, Dec 10, 2005 at 10:03:06AM +0900, pat eyler wrote:

but if this is supposed to be part of a larger program, shell
is probably the wrong way to go about it.

Why? Backticks are great.


Chad P. [ CCD CopyWrite | http://ccd.apotheon.org ]

unix virus: If you’re using a unixlike OS, please forward
this to 20 others and erase your system partition.

On Dec 11, 2005, at 7:27 AM, William J. wrote:

print s if ( seen[s] += 1 ) > 1
end

This is starting to get pointlessly obfuscated.

seen, s = Hash.new(0)
print s if ( seen[s] += 1 ) > 1 while s = gets

Stop. You’re making things hard to read for the new people.

seen = Hash.new(0)
print if ( seen[$_] += 1 ) > 1 while gets

I can’t read that so I don’t know how you expect someone new to Ruby
to read it.

I’ve never seen ‘ruby golf’ do anything positive. I find it
especially inappropriate to be performing these vile manipulations
while trying to show new people idiomatic Ruby like they asked for:

Can somebody tell me how this is to be done in Ruby? Or maybe the
Ruby
way on how to attack this whole thing. Thanks.


Eric H. - [email protected] - http://segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

Eric H. wrote:

seen[elem] = true
seen = Hash.new(0)

seen = Hash.new(0)
print if ( seen[$_] += 1 ) > 1 while gets

I can’t read that so I don’t know how you expect someone new to Ruby
to read it.

A standard Ruby idiom: instead of 3 lines . . .

if test
print “ok”
end

… . . 1 line:

print “ok” if test

Also, as in Awk, “print” with no argument prints the line just read.
Very simple. If one needs to explicitly refer to the line just read,
one uses “$_”.

And “while gets” is simpler and clearer than “ARGF.each do |elem|”.

William J. wrote:

seen = {}
end

seen, s = Hash.new(0)
print s if ( seen[s] += 1 ) > 1 while s = gets

seen = Hash.new(0)
print if ( seen[$_] += 1 ) > 1 while gets