One-Liners (#113)

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

in the

geek

“%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

#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

On Feb 11, 7:30 am, “Phrogz” [email protected] 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.caboo.se/39500

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

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.

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

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,’)

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

inserted between

1999995.99

should become “1,999,995.99”.

quiz.to_s.reverse.gsub(/(\d\d\d)(?=\d)(?!\d*.)/,"\1,").reverse

that

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 }

“GhostWheel::Expression::LookAhead”), fetch the actual class object.

quiz.split("::").inject(Object) { |par, const| par.const_get(const) }

lines will

wrap at 40 characters.

quiz.gsub!(/(.{1,40}|\S{41,})(?: +|\$\n?)/, “\1\n”)

that are

anagrams of the first word in the Array.

quiz.select { |w| w.split("").sort == quiz.first.split("").sort }

"you are

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 }

Array). A

apply the

in the

When the

get the

wondrous number

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]

three four

five] becomes {“one” => {“two” => {“three” => {“four” => “five”}}}}.

quiz.reverse.inject { |res, wrap| {wrap => res} }

James Edward G. II

On 2/12/07, James Edward G. II [email protected] wrote:

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

Here are my solutions to Quiz #113.

This quiz - as I tried to say with the wrong verb in my solution - is a
great teacher.
Well your solutions are, may I unpost mine, they feel clumsy now ;)?
Really nice. especially the commas and hash builder I am impressed.

Robert

On 2/12/07, James Edward G. II [email protected] wrote:

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

quiz.inject(Array.new) { |arr, a| arr.push(*a) }

# # 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 G. II

for the flat_flatten problem

quiz.inject{|arr,ele| [*arr].push(*ele)}

maybe you prefer your original solution but I feel the second one is
just
great too.

Cheers
Robert

On Feb 11, 4:40 pm, James Edward G. II [email protected]
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} }

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.

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

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 G. II

On 2/12/07, James Edward G. II [email protected] wrote:

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

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.

Now I just could benchmark this and be smart afterwards, but I love to
take
chances.
reverse**2 technique.
I’ll benchmark it right now…
BTW I prefer reverse ** 2 because I did not figure out the lookahead
solution

Robert

On 2/12/07, Robert D. [email protected] wrote:
here goes the benchmark ( I was right, too bad you’ll never know if I
cheated;)

the difference is only small. I think that I was wrong 'cause I really
thought that look ahead will be a killer for backtracking purpose (but I
guess it will backtrack about 1.5 times on average). Yet the reverse**2
seems a little bit faster but no need to chose one of the two algorithms
for
speed

[email protected]:~/log/ruby/quiz/113_bis 19:20:41
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
``````

[email protected]:~/log/ruby/quiz/113_bis 19:21:07
522/22 > ruby bench.rb 1_000_000
Rehearsal ------------------------------------------
Phrogz 7.140000 0.000000 7.140000 ( 7.148000)
James 6.422000 0.000000 6.422000 ( 6.452000)
-------------------------------- total: 13.562000sec

``````         user     system      total        real
``````

Phrogz 7.062000 0.000000 7.062000 ( 7.056000)
James 6.359000 0.000000 6.359000 ( 6.385000)
[email protected]:~/log/ruby/quiz/113_bis 19:21:47
523/23 > ruby bench.rb 1_000_000_000
Rehearsal ------------------------------------------
Phrogz 7.609000 0.000000 7.609000 ( 7.614000)
James 6.312000 0.000000 6.312000 ( 6.308000)
-------------------------------- total: 13.921000sec

``````         user     system      total        real
``````

Phrogz 7.484000 0.000000 7.484000 ( 7.506000)
James 6.219000 0.000000 6.219000 ( 6.268000)

Cheers
Robert

On Feb 12, 10:29 am, James Edward G. II [email protected]
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.

On Feb 12, 2007, at 12:26 PM, Robert D. wrote:

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

>> James: 1.520000 0.000000 1.520000 ( 1.528621)

END

James Edward G. II

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

On Feb 13, 2007, at 11:10 AM, Ken B. 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 G. II

On 2/12/07, James Edward G. II [email protected] wrote:

(’.’+f) : ‘’)

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:

I am a magician
well maybe not, I do not really understand, I have had the impression
before
that gmail does not work correctly all the time
nahh it’s probably just me I just steal any second on the list from my
work
as sysadmin and IP/Sec officer and maybe I should not

Nevertheless, I can see the complete code with the two methods in your
Anyway here goes the definition of the two methods(again).

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

and again?

#!/usr/bin/env ruby -w

end

>> James: 1.520000 0.000000 1.520000 ( 1.528621)

END

James Edward G. II

Robert

I will change my signature soon, maybe it is its fault

On Feb 13, 2007, at 11:56 AM, Robert D. wrote:

(h=lambda {|n| n==1 ? [1] : [n] + h[n%2 == 0 ? n/2 : n3+1] })[23]
(h=lambda {|n,lmb| n==1 ? [1] : [n] + h[n%2 == 0 ? n/2 : n
3
+1,lmb] })[23,h]

is that right?

Hmm, I wasn’t aware of this. What makes you say that?

James Edward G. II

On 2/13/07, James Edward G. II [email protected] wrote:

Exactly.

James Edward G. II

That really puts the spotlight on it, this will go away in 2.0 though
if
I understand correctly and one would need to write:

(h=lambda {|n,lmb| n==1 ? [1] : [n] + h[n%2 == 0 ? n/2 : n*3+1,lmb]
})[23,h]

is that right?

Robert