[QUIZ] One-Liners (#113)

K

Ken Bloom

On Sat, 10 Feb 2007 02:00:03 +0900, Ruby Quiz wrote:
#In all of this, +i+ is the input. Some solutions don't behave exactly the
same as the requested sample output, and some are too long. I think I
noted all such instances.

# * 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".

#this takes 83 characters
a=i.to_s.split('.');a[0]=a[0].reverse.scan(/.{1,3}/).join(',').reverse;a.join('.')

# * 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]].

i.inject([]){|cur,val| Array===val ? cur+val : cur << val}
#or
i.inject([]){|cur,val| cur+val rescue cur << val}
#(cur+val throws an error if val isn't an array)

# * Shuffle the contents of a provided Array.

i.inject([]){|cur,val| cur.insert(rand(cur.length+1),val)}

# * Given a Ruby class name in String form (like
# "GhostWheel::Expression::LookAhead"), fetch the actual class object.

eval(i)
#or
i.split("::").inject(Object){|c,v| c.const_get(v)}

# * Insert newlines into a paragraph of prose (provided in a String) so
# lines will wrap at 40 characters.

#clearly doesn't fit within 80 characters
i.split.inject([[]]){|r,w| (r[-1].inject(0){|a,b| a+b.size}+w.size)<40 ? r[-1] << w : r << [w]; r}.map{|x| x.join(' ')}.join("\n")


# * Given an Array of String words, build an Array of only those words
# that are anagrams of the first word in the Array.

i.select{|x| x.split(//).sort==i.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

i.unpack("B*")[0]
#this doesn't give me the same answer that you gave me though
#or
r="";i.each_byte{|x| r << x.to_s(2)};r

# * Provided with an open File object, select a random line of content.
x=i.readlines;x[rand(x.length)]
#or
i.find{rand<.0005 || i.eof?}
#the rules didn't say anything about the random distribution used.
#adjust the threshold as necessary

# * 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].

r=;while i!=1 do r << (i= i%2==0?i/2:i*3+1); end; r

#
# * Convert an Array of objects to nested Hashes such that %w[one two three four
# five] becomes {"one" => {"two" => {"three" => {"four" => "five"}}}}.

#neither of these gives the same answer asked for here
p=lambda{|h,k| h[k] = Hash.new(&p)};z=Hash.new(&p);i.inject(z){|ha,co|ha[co]};z
#or
z={};i.inject(z){|ha,co| ha[co]={}};z
 
S

Sharon Phillips

Hi,

I liked this quiz. Bite sized pieces I could attempt between chasing
kids :)

Here's what I came up with. Note that #6 is just a bit over the 80
char limit.

Cheers,
Dave


TEXT_FILE= '/Users/sharon/Documents/Dave/RubyQuiz/english.txt'

#* 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".
puts "-- 01 --"
quiz="1234567.89"
# soln
a=quiz.gsub(/(\d)(?=\d{3}+(\.\d*)?$)/,'\1,')
# \soln
puts a

#* 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]].
puts "\n-- 02 --"
quiz= [3, [4, 5], [2, [3]], [3, [4, 5]]]
# soln
a=quiz.inject([]){|a,q|a[a.size..a.size]=q;a}
# \soln
puts a.inspect

#* Shuffle the contents of a provided Array.
puts "\n-- 03 --"
quiz=(1..20).entries
# soln
1.upto(50){x=rand(quiz.size);quiz[x],quiz[0]=quiz[0],quiz[x]}
# \soln
puts quiz.inspect

#* Given a Ruby class name in String form (like
#"GhostWheel::Expression::LookAhead"), fetch the actual class object.
puts "\n-- 04 --"
require 'ostruct'
quiz= "OpenStruct"
# soln
a= eval(quiz).new
# \soln
puts a.class

#* Insert newlines into a paragraph of prose (provided in a String)
so lines will
#wrap at 40 characters.
puts "\n-- 05 --"
puts "---------|---------|---------|---------|"

quiz= "* Insert newlines into a paragraph of prose (provided in a
String) so lines will wrap at 40 characters."
# soln
a= quiz.gsub(/.{1,40}(?:\s|\Z)/){$&+"\n"}
# \soln
puts a

#* Given an Array of String words, build an Array of only those words
that are
#anagrams of the first word in the Array.
puts "\n-- 06 --"
quiz= %w[cat dog tac act sheep cow]
# soln
a=[];quiz[1...quiz.size].each{|x|a<<x if quiz[0].split
(//).sort==x.split(//).sort}
# /soln
puts a.inspect

#* 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
puts "\n-- 07 --"
quiz= "you are dumb"
# soln
quiz.unpack('c*').each{|c| print c==32 ? "\n" : "%b"%[c]};
# /soln

#* Provided with an open File object, select a random line of content.
puts "\n\n-- 08 --"
quiz= File.open(TEXT_FILE)
# soln
x=[];quiz.each{|line|x<<line};puts x[rand(x.size)];quiz.close
# \soln

#* 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].
puts "\n-- 09 --"
quiz=[15]
# soln
a=quiz.last; while a>1; quiz << (a=a%2==0 ? a/2 : a==1 ? 1 : a*3+1) end
# \soln
puts quiz.inspect

#* Convert an Array of objects to nested Hashes such that %w[one two
three four
#five] becomes {"one" => {"two" => {"three" => {"four" => "five"}}}}.
puts "\n-- 10 --"
quiz= %w[one two three four five]
# soln
a=quiz.reverse[1...quiz.size].inject(quiz.last){|b,c| {c=> b}}
# \soln
puts a.inspect
 
P

Phrogz

def anagrams(quiz)
n=quiz[0].split(//).sort; quiz.select {|i| i.split(//).sort == n }
end

Argh! #select is exactly what I should have used. Nice.
def hashify(quiz)
quiz.reverse.inject(){|m,i|{i=>m}}
end

How very elegant. I kept thinking there should be a way to bootstrap
the inner pair to be like all the outers, but couldn't find it. Well
done.
 
A

Alex Young

My solutions. Be gentle, this is my first quiz :) I haven't checked
these against any of the test cases that were posted, but I think a
couple of them are interesting.

# Commify numbers.
def one(quiz)
quiz.to_s.reverse.gsub(/(\d{3})(?=\d)/,'\1,').reverse
end

# Commify numbers again, but ignore any before the decimal point.
def one_alternate(quiz)
a,b=quiz.to_s.split('.');[a.reverse.gsub(/(\d{3})(?=\d)/,'\1,').reverse,b].join('.')
end

# One-level flatten().
def two(quiz)
r=[];quiz.each{|a|r+=[*a]};r
end

# Array shuffling the noddy way.
def three(quiz)
r={};quiz.each{|a|r[a]=nil};r.keys
end

# Array shuffling the proper way.
def three_alternate(quiz)
r=[];quiz.size.times{r<<quiz.delete_at(rand(quiz.size))};r
end

# Getting classes from strings.
def four(quiz)
quiz.split('::').inject(Object){|m,r|m=m.const_get(r)}
end

# Line wrapping.
def five(quiz)
r='';quiz.size.times{|i|r<<quiz.chr;i%40==39?r<<"\n":1};r
end

# Finding anagrams.
def six(quiz)
(c=quiz.map{|a|[a,a.split('').sort.join]}).select{|b|b[1]==c[0][1]}.map{|d|d[0]}
end

# Binary strings.
def seven(quiz)
quiz.split(' ').map{|s|s.unpack('B*')[0][1..-1]}*$/
end

# Random lines.
def eight(quiz)
(a=quiz.readlines)[rand(a.size)]
end

# Wondrous numbers
def nine(quiz)
a=quiz;r=[a];r<<(a=a%2==0?a/2:1+a*3)while a!=1;r
end

# Hash construction
def ten(quiz)
(a = quiz.pop;quiz).reverse.inject(a){|m,r| m = {r => m}}
end
 
E

Eric I.

# One-level flatten().
r=[];quiz.each{|a|r+=[*a]};r

Elegantly small!

When I saw that, I thought that it could definitely be shortened by
using an inject. After all, there'd be no assignments of r, no final
returning of r, no semicolons. But when all was said and done, it
ended up being the same length. Compare:

quiz.inject([]){|r,a|r+[*a]}
r=[];quiz.each{|a|r+=[*a]};r

Oh well....

Eric
 
K

Krishna Dole

I don't think my solutions contribute much that is new, but you can
see them below and on pastie: http://pastie.caboo.se/39741.

I thought it was interesting that many previous solutions to the
commify problem posted on lists and on RubyForge fail for numbers like
0.23423423.

Looking at others' solutions, I really like Robert Dober's
sort_by{rand} solution to the array shuffle.

cheers,
Krishna

----------------------------------------------------------------
require 'test/unit'
# test setup mostly borrowed from Jamie Macey

class OneLiner
class << self

# this was the hardest one for me. this answer is not
# entirely my own, as it was inspired by
# http://rubyforge.org/snippet/detail.php?type=snippet&id=8
# (which does not work for numbers like 0.234234234234)
def commaize(quiz)
quiz.to_s.sub(/^(-*)(\d+)/){|m| $1 + $2.gsub(/(\d)(?=\d{3}+$)/, '\1,')}
end

def flatten_once(quiz)
quiz.inject([]){|n, e| e.is_a?(Array) ? n + e : n << e }
end

def shuffle(quiz)
a = quiz.dup; Array.new(a.size).map{|i| a.delete_at(rand(a.size)) }
end

def get_class(quiz)
require quiz.downcase.split("::")[0..-2].join("/"); eval quiz
end

def wrap_text(quiz)
quiz.gsub(/(.{1,40}(\s|$))/, '\1' + "\n").chop
end

def find_anagrams(quiz)
quiz.select{|w| w.scan(/./).sort == quiz[0].scan(/./).sort}
end

def binarize(quiz)
s = ""; quiz.each_byte {|c| c == 32 ? s << "\n" : s << "%b" % c}; s
end

# using #readlines would be easiest, but unlike that, this solution
# should work fine on files that are too big to hold in memory.
# unfortunately, it is more than 80 chars when using a variable
# named 'quiz'
def random_line(quiz)
i = rand(quiz.each{|l|}.lineno); quiz.rewind; quiz.each{|l|
return l if quiz.lineno == i+1}
end

# i know. it's 6 lines, not one. and more than 80 chars :(
def wondrous_sequence(quiz)
a = [n = quiz]; while n != 1; n = (n % 2 > 0 ? n * 3 + 1 : n /
2); a << n; end; a
end

# i guess it is cheating to use recursion (two lines)
# but it worked too nicely to resist here.
def nested_hash(quiz)
quiz.size > 1 ? {quiz[0] => nested_hash(quiz[1..-1])} : quiz[0]
end
end
end

require 'tempfile'
class TestOneLiner < Test::Unit::TestCase
# 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".
def test_commaize
assert_equal "995", OneLiner.commaize(995)
assert_equal "1,995", OneLiner.commaize(1995)
assert_equal "12,995", OneLiner.commaize(12995)
assert_equal "123,995", OneLiner.commaize(123995)
assert_equal "1,234,995", OneLiner.commaize(1234995)
assert_equal "1,234,567,890,995", OneLiner.commaize(1234567890995)
assert_equal "99,995.992349834", OneLiner.commaize(99995.992349834)
assert_equal "0.992349834", OneLiner.commaize(0.992349834)
assert_equal "-0.992349834", OneLiner.commaize(-0.992349834)
assert_equal "999,995.99", OneLiner.commaize(999995.99)
assert_equal "-1,999,995.99", OneLiner.commaize(-1999995.99)
end

# 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]].
def test_flatten_once
ary = [1, [2, [3, 4]]]
flatter_ary = [1, 2, [3, 4]]
assert_equal flatter_ary, OneLiner.flatten_once(ary)
end

# Shuffle the contents of a provided Array.
def test_shuffle
ary = [3,1,4,1,5,9]
shuffled_ary = OneLiner.shuffle(ary)
assert_not_equal ary, shuffled_ary
assert_equal ary.sort, shuffled_ary.sort
end

# Given a Ruby class name in String form (like
# "GhostWheel::Expression::LookAhead"), fetch the actual class object.
def test_get_class
assert_equal Test::Unit::TestCase,
OneLiner.get_class("Test::Unit::TestCase")
end

# Insert newlines into a paragraph of prose (provided in a String) so
# lines will wrap at 40 characters.
def test_wrap_text
wrapped = "Insert newlines into a paragraph of " + "\n" +
"prose (provided in a String) so lines " + "\n" +
"will wrap at 40 characters."
paragraph = "Insert newlines into a paragraph of " +
"prose (provided in a String) so lines " +
"will wrap at 40 characters."
assert_equal wrapped, OneLiner.wrap_text(paragraph)
end

# Given an Array of String words, build an Array of only those words that
# are anagrams of the first word in the Array.
def test_find_anagrams
anagrams = %w(tac cat act)
assert_equal anagrams, OneLiner.find_anagrams(%w(tac bat cat rat act))
end


# 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
def test_binarize
output = "111100111011111110101" + "\n" +
"110000111100101100101" + "\n" +
"1100100111010111011011100010"
assert_equal output, OneLiner.binarize("you are dumb")
end

# Provided with an open File object, select a random line of content.
#
# NOTE: This test assumes you're using File#read to get the string data
# from the file - if doing otherwise, update the test?
def test_random_line
f = Tempfile.new("foo")
f.print("development:
adapter: mysql
database: redvase_development
host: localhost
username: root
password:")
f.flush
f.rewind
lines = f.readlines
line = OneLiner.random_line(f)
assert_equal true, lines.include?(line)

end

# 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].
def test_wondrous_sequence
seq = [23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]
assert_equal seq, OneLiner.wondrous_sequence(23)
end

# Convert an Array of objects to nested Hashes such that %w[one two three
# four five] becomes {"one" => {"two" => {"three" => {"four" => "five"}}}}.
def test_nested_hash
hash = {:eek: => {:t => {:t => {:f => :f}}}}
assert_equal hash, OneLiner.nested_hash([:eek:, :t, :t, :f, :f])
end
end
 
A

Alex Young

Robert said:
# One-level flatten().
r=[];quiz.each{|a|r+=[*a]};r

Elegantly small!

When I saw that, I thought that it could definitely be shortened by
using an inject. After all, there'd be no assignments of r, no final
returning of r, no semicolons. But when all was said and done, it
ended up being the same length. Compare:

quiz.inject([]){|r,a|r+[*a]}
Given the equal lengths, I prefer this - the r=[];...;r idiom strikes me
as rather ugly.
r=[];quiz.each{|a|r+=[*a]};r

Oh well....

Eric


Comparing this with James' solution we can it down to
quiz.inject{|r,a|[*r]+[*a]}
Wow :)
 
S

Simon Kröger

J

James Edward Gray II

Hi All! Hi James! Hi Robert!

just wanted to note that there seems to be not a single message
from Robert on the newsgroup side of life.

Yes, Robert's messages are sent as multipart/alternative. Here's the =20=

header from his latest one:

Content-Type: multipart/alternative; boundary=3D"----=20
=3D_Part_86388_20605457.1171389368901"

The Gateway's current Usenet host doesn't support this message =20
format. (It's not technically a legal Usenet post.) You can read =20
more about this at:

http://blog.grayproductions.net/articles/2006/12/01/what-is-the-ruby-=20
talk-gateway

James Edward Gray II
 
S

Simon Kröger

James said:
Yes, Robert's messages are sent as multipart/alternative. Here's the
header from his latest one:

Content-Type: multipart/alternative;
boundary="----=_Part_86388_20605457.1171389368901"

The Gateway's current Usenet host doesn't support this message format.
(It's not technically a legal Usenet post.) You can read more about
this at:

http://blog.grayproductions.net/articles/2006/12/01/what-is-the-ruby-talk-gateway


James Edward Gray II

Sorry for not reading that before, i wasn't aware of that resource.

So Robert, would you please configure your mail-client?
(I would really like to read your posts)

cheers

Simon
 
R

Robert Dober

Sorry for not reading that before, i wasn't aware of that resource.

So Robert, would you please configure your mail-client?
(I would really like to read your posts)

cheers

Simon
Thanx
Did you get this one?

I just switched off "Rich formatting" I did not find much else to do :(

Robert

--=20
We have not succeeded in answering all of our questions.
In fact, in some ways, we are more confused than ever.
But we feel we are confused on a higher level and about more important thin=
gs.
-Anonymous
 
R

Robert Dober

You do not have to do any more than that. Thanks.


cheers

Simon
Great; great, thx to you and apologies to the list for the noise.
But it might be a good thing to know for all fellow g-mailers :)

Cheers
Robert

--=20
We have not succeeded in answering all of our questions.
In fact, in some ways, we are more confused than ever.
But we feel we are confused on a higher level and about more important thin=
gs.
-Anonymous
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top