[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

[SOLUTION] One-Liners (#113

Gavin Kistner

2/11/2007 2:31:00 PM

Here are my solutions to Quiz #113. For some of them I just couldn't
help but to provide a couple variations.

Because I'm a terrible golfer, most strive for elegance (in some form)
over terseness.


# 1 - Commafy Numerics
i,f=quiz.to_s.split('.'); i.gsub(/(\d)(?=\d{3}+$)/,'\\1,') + (f ?
('.'+f) : '')



# 2 - Flatten_Once
a=[]; quiz.each{ |x| Array===x ? a.concat(x) : a<<x }; a



# 3 - Shuffle Array
quiz.sort_by{ rand }



# 4 - Resolve class (and other constants) from string
quiz.split( '::' ).inject( Module ){ |r,o| r.const_get(o) }
#...or, by cheating
eval(quiz)



#5 - Paragraph Wrapping - extra work to not put a new line on the last
line
quiz.gsub( /^(.{1,40})($|[ \t]+)/ ){ $2.empty? ? $1 : "#{$1}\n" }



#6 - Anagrams - assuming that the original word shouldn't be in the
output...
a=[]; r=quiz.shift.split('').sort; quiz.each{|w|a<<w if
w.split('').sort==r}; a
#...or, if the original word should be included
a=[]; r=quiz[0].split('').sort; quiz.each{ |w| a<<w if
w.split('').sort==r }; a



#7 - String to Binary String, the geeky way
o=''; quiz.each_byte{|b| o << ( b==32 ? "\n" : ('%b' % b) ) }; o
#...or slightly more 'rubyish'...
quiz.split(' ').map{|s| o=''; s.each_byte{|b| o << b.to_s(2) };
o }.join("\n")
#...but what's more rubyish than nested #maps and pulling bytes from
strings? ;)
quiz.split(' ').map{|s| s.scan(/./).map{|c| '%b' %
c[0] }.join }.join("\n")

# By the way, I have to say that if the Think Geek t-shirts are really
in the
# form provided, they are terrible #representations of geekiness. What
geek
# would strip the leading zeros from the bits in a byte? I'd replace
"%b" with
# "%08b" above for a better representation (and use it instead of
to_s(2)).



#8 - Random line from file - if you run out of memory, go buy more
RAM ;)
all=quiz.readlines; all[ rand(all.length) ]



#9 - Wondrous number path
a=[n=quiz]; while n>1; a << ( n%2==0 ? n/=2 : n=(n*3)+1 ); end; a



#10 - Array to Nested Hash, direct indexing...
a=quiz; h={a[-2]=>a[-1]}; (a.size-3).downto(0){ |i| h={a[i]=>h} }; h
#...or a slightly different way...
a=quiz; y,z=a[-2..-1]; h={y=>z}; a[0..-3].reverse.each{ |o|
h={o=>h} }; h
#...or poppin' values for a tighter format...
a=quiz; z,y=a.pop,a.pop; h={y=>z}; a.reverse.each{ |o| h={o=>h} }; h
#...and one last, just because I love Hash.[]
a=quiz.reverse; h=Hash[a.shift,a.shift].invert; a.each{ |o|
h={o=>h} }; h

11 Answers

Gavin Kistner

2/11/2007 2:44:00 PM

0

On Feb 11, 7:30 am, "Phrogz" <g...@refinery.com> wrote:
> Here are my solutions to Quiz #113. For some of them I just couldn't
> help but to provide a couple variations.

Bah, of course the 80-char lines wrapped and got confusing with my
comments. Here's my solution again, with syntax highlighting:
http://pastie.cabo...

And here is the actual code I originally wrote to test most of the
solutions:
http://pastie.cabo...

Ken Bloom

2/11/2007 7:16:00 PM

0

On Sun, 11 Feb 2007 06:30:52 -0800, Phrogz wrote:

> Here are my solutions to Quiz #113. For some of them I just couldn't
> help but to provide a couple variations.
>
> Because I'm a terrible golfer, most strive for elegance (in some form)
> over terseness.
>
>
> # 1 - Commafy Numerics
> i,f=quiz.to_s.split('.'); i.gsub(/(\d)(?=\d{3}+$)/,'\\1,') + (f ?
> ('.'+f) : '')

Good answer. you helped me golf mine down a little bit by getting rid of
array indexing:

i,f=i.to_s.split('.');"#{i.reverse.scan(/.{1,3}/).join(',').reverse}.#{f}"

>
> # 3 - Shuffle Array
> quiz.sort_by{ rand }

I feel stupid for taking such a longer answer. And I've used sort_by{rand}
too to do this, if not in Ruby then in SQL, so I feel stupid for not
thinking of it in this context.]

mine, as I posted elsewhere was:
i.inject([]){|cur,val| cur.insert(rand(cur.length+1),val)}


> #5 - Paragraph Wrapping - extra work to not put a new line on the last
> line
> quiz.gsub( /^(.{1,40})($|[ \t]+)/ ){ $2.empty? ? $1 : "#{$1}\n" }

I like this one a lot. My only answer was way too long, and far more
complicated.



--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu...

Ken Bloom

2/11/2007 8:37:00 PM

0

On Sun, 11 Feb 2007 19:15:44 +0000, Ken Bloom wrote:

> On Sun, 11 Feb 2007 06:30:52 -0800, Phrogz wrote:
>
>> Here are my solutions to Quiz #113. For some of them I just couldn't
>> help but to provide a couple variations.
>>
>> Because I'm a terrible golfer, most strive for elegance (in some form)
>> over terseness.
>>
>>
>> # 1 - Commafy Numerics
>> i,f=quiz.to_s.split('.'); i.gsub(/(\d)(?=\d{3}+$)/,'\\1,') + (f ?
>> ('.'+f) : '')
>
> Good answer. you helped me golf mine down a little bit by getting rid of
> array indexing:
>
> i,f=i.to_s.split('.');"#{i.reverse.scan(/.{1,3}/).join(',').reverse}.#{f}"

Another answer, based on yours, this one is exactly one expression (no
semicolons):
quiz.to_s.gsub(/(\d)(?=\d{3}+#{quiz.to_s=~/\./?/\./:/$/})/,'\\1,')


--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu...

James Gray

2/11/2007 11:41:00 PM

0

On Feb 11, 2007, at 8:35 AM, Phrogz wrote:

> Here are my solutions to Quiz #113.

When I built the quiz, I used the following solutions to reality-
check myself. (Making sure I could find a viable answer.)

#
# Given a Numeric, provide a String representation with commas
inserted between
# each set of three digits in front of the decimal. For example,
1999995.99
# should become "1,999,995.99".
#
quiz.to_s.reverse.gsub(/(\d\d\d)(?=\d)(?!\d*\.)/,"\\1,").reverse

#
# Given a nested Array of Arrays, perform a flatten()-like operation
that
# removes only the top level of nesting. For example, [1, [2, [3]]]
would
# become [1, 2, [3]].
#
quiz.inject(Array.new) { |arr, a| arr.push(*a) }

# Shuffle the contents of a provided Array.
quiz.sort_by { rand }

#
# Given a Ruby class name in String form (like
# "GhostWheel::Expression::LookAhead"), fetch the actual class object.
#
quiz.split("::").inject(Object) { |par, const| par.const_get(const) }

#
# Insert newlines into a paragraph of prose (provided in a String) so
lines will
# wrap at 40 characters.
#
quiz.gsub!(/(.{1,40}|\S{41,})(?: +|$\n?)/, "\\1\n")

#
# Given an Array of String words, build an Array of only those words
that are
# anagrams of the first word in the Array.
#
quiz.select { |w| w.split("").sort == quiz.first.split("").sort }

#
# Convert a ThinkGeek t-shirt slogan (in String form) into a binary
# representation (still a String). For example, the popular shirt
"you are
# dumb" is actually printed as:
#
# 111100111011111110101
# 110000111100101100101
# 1100100111010111011011100010
#
quiz.split("").map { |c| c == " " ? "\n" : c[0].to_s(2) }.join

# Provided with an open File object, select a random line of content.
quiz.inject { |choice, line| rand < 1/quiz.lineno.to_f ? line : choice }

#
# Given a wondrous number Integer, produce the sequence (in an
Array). A
# wondrous number is a number that eventually reaches one, if you
apply the
# following rules to build a sequence from it. If the current number
in the
# sequence is even, the next number is that number divided by two.
When the
# current number is odd, multiply that number by three and add one to
get the
# next number in the sequence. Therefore, if we start with the
wondrous number
# 15, the sequence is [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20,
10, 5, 16,
# 8, 4, 2, 1].
#
Hash.new { |h, n| n == 1 ? [1] : [n] + h[n % 2 == 0 ? n/2 : n*3+1] }
[quiz]

#
# Convert an Array of objects to nested Hashes such that %w[one two
three four
# five] becomes {"one" => {"two" => {"three" => {"four" => "five"}}}}.
#
quiz.reverse.inject { |res, wrap| {wrap => res} }

James Edward Gray II


Gavin Kistner

2/12/2007 5:59:00 AM

0

On Feb 11, 4:40 pm, James Edward Gray II <j...@grayproductions.net>
wrote:
> quiz.to_s.reverse.gsub(/(\d\d\d)(?=\d)(?!\d*\.)/,"\\1,").reverse
> quiz.inject(Array.new) { |arr, a| arr.push(*a) }
> quiz.sort_by { rand }
> quiz.split("::").inject(Object) { |par, const| par.const_get(const) }
> quiz.gsub!(/(.{1,40}|\S{41,})(?: +|$\n?)/, "\\1\n")
> quiz.select { |w| w.split("").sort == quiz.first.split("").sort }
> quiz.split("").map { |c| c == " " ? "\n" : c[0].to_s(2) }.join
> quiz.inject { |choice, line| rand < 1/quiz.lineno.to_f ? line : choice }
> Hash.new{|h, n| n==1 ? [1] : [n] + h[n%2 == 0 ? n/2 : n*3+1] }[quiz]
> quiz.reverse.inject { |res, wrap| {wrap => res} }

What I particularly admire about your solutions is that they are all
single- or chained-statements. None of the "a=[];...;a" nonsense that
I mucked about with. I wish I had been sure that it was possible to do
this for all solutions, so that I would have looked harder.

I can't tell if I think the reverse/regexp/reverse technique you (and
many others) used for the first problem is more or less elegant than a
single regexp on the integer portion. I suspect that mine is faster at
runtime...but speed is rarely an appropriate measure of elegance.

Kudos on the memoizing wondrous number, btw. :)

James Gray

2/12/2007 5:30:00 PM

0

On Feb 12, 2007, at 12:00 AM, Phrogz wrote:

> What I particularly admire about your solutions is that they are all
> single- or chained-statements.

Thank you.

> I can't tell if I think the reverse/regexp/reverse technique you (and
> many others) used for the first problem is more or less elegant than a
> single regexp on the integer portion. I suspect that mine is faster at
> runtime...but speed is rarely an appropriate measure of elegance.

I'm pretty sure I learned that reverse(), gsub(), and reverse() trick
from Perl's FAQ years ago. I just checked now though and the answer
is not what I recall, so maybe I am misremembering that.

> Kudos on the memoizing wondrous number, btw. :)

It's not actually. I never assign the Hash value. ;)

James Edward Gray II

Gavin Kistner

2/12/2007 5:57:00 PM

0

On Feb 12, 10:29 am, James Edward Gray II <j...@grayproductions.net>
wrote:
> On Feb 12, 2007, at 12:00 AM, Phrogz wrote:
> > > Hash.new{|h, n| n==1 ? [1] : [n] + h[n%2 == 0 ? n/2 : n*3+1] }[quiz]
> > Kudos on the memoizing wondrous number, btw. :)
>
> It's not actually. I never assign the Hash value. ;)

Interesting point. (And, of course, it wouldn't be useful if it
memoized the result for a single call to the function.) I think it's
interesting because this pattern really allows you to (ab)use the
block form of Hash as a lambda that passes a reference to itself as
one of its arguments. Very convenient for one-liners.

James Gray

2/12/2007 7:04:00 PM

0

On Feb 12, 2007, at 12:26 PM, Robert Dober wrote:

> 521/21 > cat bench.rb
> require 'benchmark'
>
> array = (1..100000).map { rand * (ARGV.first||1_000_000).to_f }
>
> def phrogz quiz
> i,f=quiz.to_s.split('.'); i.gsub(/(\d)(?=\d{3}+$)/,'\\1,') + (f ?
> ('.'+f) : '')
> end
> def james quiz
> quiz.to_s.reverse.gsub(/(\d\d\d)(?=\d)(?!\d*\.)/,"\\1,").reverse
> end
>
>
> Benchmark.bmbm do |x|
> x.report("Phrogz") {array.map{ |e| phrogz(e) }}
> x.report("James") {array.map{ |e| james(e) }}
> end

How does this code work? You pass arguments to methods we don't
see. The ones we do see don't even accept arguments.

The results look right though:

#!/usr/bin/env ruby -w

require "benchmark"

def phrogz(num)
i,f=num.to_s.split('.'); i.gsub(/(\d)(?=\d{3}+$)/,'\\1,') + (f ?
('.'+f) : '')
end

def james(num)
num.to_s.reverse.gsub(/(\d\d\d)(?=\d)(?!\d*\.)/,"\\1,").reverse
end

TESTS = Array.new(100_000) { rand(1_000_000) + 1.to_f / (rand(1_000)
+ 1) }
Benchmark.bmbm do |results|
results.report("Phrogz:") { TESTS.each { |n| phrogz(n) } }
results.report("James:") { TESTS.each { |n| james(n) } }
end
# >> Rehearsal -------------------------------------------
# >> Phrogz: 1.690000 0.010000 1.700000 ( 1.700985)
# >> James: 1.550000 0.010000 1.560000 ( 1.557882)
# >> ---------------------------------- total: 3.260000sec
# >>
# >> user system total real
# >> Phrogz: 1.690000 0.010000 1.700000 ( 1.703213)
# >> James: 1.520000 0.000000 1.520000 ( 1.528621)

__END__

James Edward Gray II

Ken Bloom

2/13/2007 5:08:00 PM

0

>>> Hash.new{|h, n| n==1 ? [1] : [n] + h[n%2 == 0 ? n/2 : n*3+1] }[quiz]
>> Kudos on the memoizing wondrous number, btw. :)
> It's not actually. I never assign the Hash value. ;)

So it's equivalent to:
(h=lambda {|n| n==1 ? [1] : [n] + h[n%2 == 0 ? n/2 : n*3+1] })[23]

--Ken

--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu...

James Gray

2/13/2007 5:42:00 PM

0

On Feb 13, 2007, at 11:10 AM, Ken Bloom wrote:

>>>> Hash.new{|h, n| n==1 ? [1] : [n] + h[n%2 == 0 ? n/2 : n*3+1] }
>>>> [quiz]
>>> Kudos on the memoizing wondrous number, btw. :)
>> It's not actually. I never assign the Hash value. ;)
>
> So it's equivalent to:
> (h=lambda {|n| n==1 ? [1] : [n] + h[n%2 == 0 ? n/2 : n*3+1] })[23]

Exactly.

James Edward Gray II