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? :wink:
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 :wink:
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

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

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

Applying your genius to your genius we get
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} }

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

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

It’s not actually. I never assign the Hash value. :wink:

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.
I guess your positive lookahead assertion will be slower than James’
reverse**2 technique.
I’ll benchmark it right now…
BTW I prefer reverse ** 2 because I did not figure out the lookahead
solution :wink:

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

robert@PC:~/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

robert@PC:~/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)
robert@PC:~/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. :slight_smile:

It’s not actually. I never assign the Hash value. :wink:

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

>> 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 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. :slight_smile:
It’s not actually. I never assign the Hash value. :wink:

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. :slight_smile:
It’s not actually. I never assign the Hash value. :wink:

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 :wink:
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 :frowning:

Nevertheless, I can see the complete code with the two methods in your
reply to the post!
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

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

Robert

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

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