[QUIZ] One-Liners Mashup (#177 again)

M

Matthew Moss

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Quiz 2:

1. This week only -- no waiting period!

2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Quiz 2. Until then,
please visit the temporary website at

<http://splatbang.com/rubyquiz/>.

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby Talk follow the discussion. Please reply to
the original quiz message, if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Apologies for being late today... 'twas distracted by my English
report!

## One-Liners Mashup (#177)

This week is going to be very informal, and without any particular
task or submission. It's hunting season, and we're hunting one-liners.

Basically, we'll start with the simple problem I've presented below.
Your solution must fit in one line. (Golfing is okay, but not
necessary. One line *generally* means about 80 chars wide, but we're
flexible here.) If you are writing a method, the `def foo(args)` and
`end` (and `class Whatever` and `end` for adding methods to a class)
doesn't count... the body of the method will.

Of course, your solutions should be generally useful, and not hard-
coded to solve any particular example used to illustrate what the
solution should do.

Post your solution AND a followup problem for others to solve. Repeat
ad nauseum (or until about Wed/Thu).

Ready? Here goes. First problem...
You should know this pattern well:
[:eek:ne, "two", 4] * 3
=> [:eek:ne, "two", 4, :eek:ne, "two", 4, :eek:ne, "two", 4]

Write a single line method on Array that does this instead:
[:eek:ne, "two", 4].repeat(3)
=> [:eek:ne, :eek:ne, :eek:ne, "two", "two", "two", 4, 4, 4]
 
D

Daniel Moore

def repeat(i)
r = []; each { |x| r.push(*([x] * i)) }; r
end

Challenge:
Print out a Serpinski carpet.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Quiz 2:

1. This week only -- no waiting period!

2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Quiz 2. Until then,
please visit the temporary website at

<http://splatbang.com/rubyquiz/>.

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby Talk follow the discussion. Please reply to
the original quiz message, if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

Apologies for being late today... 'twas distracted by my English
report!

## One-Liners Mashup (#177)

This week is going to be very informal, and without any particular
task or submission. It's hunting season, and we're hunting one-liners.

Basically, we'll start with the simple problem I've presented below.
Your solution must fit in one line. (Golfing is okay, but not
necessary. One line *generally* means about 80 chars wide, but we're
flexible here.) If you are writing a method, the `def foo(args)` and
`end` (and `class Whatever` and `end` for adding methods to a class)
doesn't count... the body of the method will.

Of course, your solutions should be generally useful, and not hard-
coded to solve any particular example used to illustrate what the
solution should do.

Post your solution AND a followup problem for others to solve. Repeat
ad nauseum (or until about Wed/Thu).

Ready? Here goes. First problem...
You should know this pattern well:
[:eek:ne, "two", 4] * 3
=> [:eek:ne, "two", 4, :eek:ne, "two", 4, :eek:ne, "two", 4]

Write a single line method on Array that does this instead:
[:eek:ne, "two", 4].repeat(3)
=> [:eek:ne, :eek:ne, :eek:ne, "two", "two", "two", 4, 4, 4]
 
P

Patrick Doyle

def repeat(i)
r = []; each { |x| r.push(*([x] * i)) }; r
end
Here's mine:
def repeat(i)
self.map {|x| [x] * i}.flatten
end

I don't appreciate Ruby syntax enough to understand the significance
of the *(...) construct in Daniel's solution. What does that do? Can
you show an example where the results are different than my solution?

--wpd
 
J

James Gray

First problem...
You should know this pattern well:
[:eek:ne, "two", 4] * 3
=> [:eek:ne, "two", 4, :eek:ne, "two", 4, :eek:ne, "two", 4]

Write a single line method on Array that does this instead:
[:eek:ne, "two", 4].repeat(3)
=> [:eek:ne, :eek:ne, :eek:ne, "two", "two", "two", 4, 4, 4]

class Array; def repeat(n) zip(*([self] * (n - 1))).flatten end end
Post your solution AND a followup problem for others to solve.

Given the class:

class Data2D
def initialize
@data = [ ] # in row major form
end

def add_row(*row)
@data << row
end
end

And this setup for an object:

data = Data2D.new
data.add_row(1, 2, 3, 4)
data.add_row(5, 6, 7, 8)

Define a [] method for the class that makes this form of access
possible:

x = 2
y = 1
data[x][y] # => 7

James Edward Gray II
 
P

Patrick Doyle

Given the class:
class Data2D
def initialize
@data = [ ] # in row major form
end

def add_row(*row)
@data << row
end
end

And this setup for an object:

data = Data2D.new
data.add_row(1, 2, 3, 4)
data.add_row(5, 6, 7, 8)

Define a [] method for the class that makes this form of access possible:

x = 2
y = 1
data[x][y] # => 7
How about

def [](i)
@data.map {|row| row}
end
Oops, I'll have to think about that... but not tonight

... on a completely different topic... I've noticed that whenever I
post a message to (e-mail address removed) from my gmail account, I get
the message twice in my inbox, making me wonder three things...
1) Does everybody get my messages twice? If so, I humbly apologize
and will stop posting immediately as I can see where this could be
just a tiny little bit annoying.
2) Does anybody else have this problem? If so
3) How did you solve it (assuming it's a solvable problem)?

--wpd
 
D

Daniel Moore

It splats an array into it's components:
http://theplana.wordpress.com/2007/03/03/ruby-idioms-the-splat-operator/
I couldn't use flatten because it would destroy nested arrays.

[[1,2],[3,4]].repeat(2) => [1, 2, 1, 2, 3, 4, 3, 4] #With flatten

[[1,2],[3,4]].repeat(2) => [[1, 2], [1, 2], [3, 4], [3, 4]] #Without flatten

def repeat(i)
r = []; each { |x| r.push(*([x] * i)) }; r
end
Here's mine:
def repeat(i)
self.map {|x| [x] * i}.flatten
end

I don't appreciate Ruby syntax enough to understand the significance
of the *(...) construct in Daniel's solution. What does that do? Can
you show an example where the results are different than my solution?

--wpd
 
B

Bill Kelly

From: "Matthew Moss said:
Ready? Here goes. First problem...
You should know this pattern well:
[:eek:ne, "two", 4] * 3
=> [:eek:ne, "two", 4, :eek:ne, "two", 4, :eek:ne, "two", 4]

Write a single line method on Array that does this instead:
[:eek:ne, "two", 4].repeat(3)
=> [:eek:ne, :eek:ne, :eek:ne, "two", "two", "two", 4, 4, 4]


# SOLUTION 1:
# Partial solution, we would need a flatten(1) to prevent it from
# messing up nested arrays like [:eek:ne, "two", [3]] -- since flatten
# unarrays recursively.

class Array; def repeat(n); ([self]*n).transpose.flatten; end; end


# SOLUTION 2:
# Avoids flatten, so won't break nested arrays:

class Array; def repeat(n); ([self]*n).transpose.inject([]){|a,e| a += e}; end; end



--------------
NEW CHALLENGE:
--------------

# Given one or more input filenames on the command line,
# report the number of unique IP addresses found in all the
# data.
#
# (For our purposes, an IP address may simply be considered
# four integerers separated by dots, e.g.: 6.54.123.9 )
#
# Optionally, the solution should read stdin if no filenames
# were specified.
#
# Preferably, the solution should be expressed in the form of
# a ruby command-line invocation. (Optional.)



Regards,

Bill
 
D

David Masover

Given the class:

class Data2D
def initialize
@data = [ ] # in row major form
end

def add_row(*row)
@data << row
end
end

And this setup for an object:

data = Data2D.new
data.add_row(1, 2, 3, 4)
data.add_row(5, 6, 7, 8)

Define a [] method for the class that makes this form of access possible:

x = 2
y = 1
data[x][y] # => 7
How about

def [](i)
@data.map {|row| row}
end


Curses! You beat me to it, so I wrote a more complex solution:

class Data2D
def [](x)
d=@data; Class.new{ define_method('[]') {|y| d[y][x]}}.new
end
end

Counting spaces, it's 64 characters, so it still fits. It has the advantage of
probably being faster on very large datasets, at least for that single
lookup, as no array splicing is done.

I didn't really have a problem in mind, but here's an easy one: Write an []=
method to solve the following:

obj = YourClass.new
obj['answer'] = 42
obj.answer # => 42
 
J

James Gray

Given the class:

class Data2D
def initialize
@data = [ ] # in row major form
end

def add_row(*row)
@data << row
end
end

And this setup for an object:

data = Data2D.new
data.add_row(1, 2, 3, 4)
data.add_row(5, 6, 7, 8)

Define a [] method for the class that makes this form of access
possible:

x = 2
y = 1
data[x][y] # => 7
How about

def [](i)
@data.map {|row| row}
end


Curses! You beat me to it, so I wrote a more complex solution:

class Data2D
def [](x)
d=@data; Class.new{ define_method('[]') {|y| d[y][x]}}.new
end
end

Counting spaces, it's 64 characters, so it still fits. It has the
advantage of
probably being faster on very large datasets, at least for that single
lookup, as no array splicing is done.


When I wrote the problem, I was thinking of this solution:

class Data2D; def [](x) lambda { |y| @data[y][x] } end

James Edward Gray II
 
J

James Gray

--------------
NEW CHALLENGE:
--------------

# Given one or more input filenames on the command line, # report
the number of unique IP addresses found in all the
# data.
#
# (For our purposes, an IP address may simply be considered
# four integerers separated by dots, e.g.: 6.54.123.9 )
#
# Optionally, the solution should read stdin if no filenames
# were specified.
#
# Preferably, the solution should be expressed in the form of
# a ruby command-line invocation. (Optional.)

ruby -e 'p ARGF.read.scan(/\d{1,3}(\.\d{1,3}){3}/).uniq.size'

New puzzle: Provide a one-liner that can wrap a body of text at a
requested maximum length.

James Edward Gray II
 
S

Sebastian Hungerecker

James said:
New puzzle: =A0Provide a one-liner that can wrap a body of text at a =A0
requested maximum length.

Wasn't that a question in the old one liner quiz?
Anyway (without looking it up):
text.gsub(/.{1,80}/,"\\0\n")
Or if you want to avoid breaking in the middle of words:
text.gsub(/(.{1,80})\s+/, "\\1\n")
(you'll have lines above 80 chars if there's a single word with more than 8=
0=20
characters).

Next question:
Sort an array of words by the words' values where a word's value is the
sum of the values of its letters and a letter's value is its position in
the alphabet. So the value of "Hello" is 8+5+12+12+15.

=2D-=20
Jabber: (e-mail address removed)
ICQ: 205544826
 
H

Holger Mack

[Note: parts of this message were removed to make it a legal post.]

2008/9/20 Sebastian Hungerecker said:
Next question:
Sort an array of words by the words' values where a word's value is the
sum of the values of its letters and a letter's value is its position in
the alphabet. So the value of "Hello" is 8+5+12+12+15.


class Array; def sortval() sort {|x,y| x.upcase.sum-x.length*64 <=>
y.upcase.sum-y.length*64};end;end

Solution works fine, if array countains only words of only letters. Now I
know, what sum() is for ;-)

----------------------
NEXT QUIZ

Write a function per(n) which returns the periodicity of 1/n, i.e.
per(3) => 1
per(4) => 0
per(7) => 6
per(11) => 2


Holger
 
B

Bill Kelly

From: "Sebastian Hungerecker said:
Wasn't that a question in the old one liner quiz?
Anyway (without looking it up):
text.gsub(/.{1,80}/,"\\0\n")
Or if you want to avoid breaking in the middle of words:
text.gsub(/(.{1,80})\s+/, "\\1\n")
(you'll have lines above 80 chars if there's a single word with
more than 80 characters).

Indeed, I recall this from a previous ruby-talk thread... my
solution was like your 2nd one, above.... However, I seem to
recall someone had come up with an elegant regexp to actually
wrap words *on-or-before* the boundary.

(I remember being impressed. Wish I could recall the
technique. :)

Next question:
Sort an array of words by the words' values where a word's value is the
sum of the values of its letters and a letter's value is its position in
the alphabet. So the value of "Hello" is 8+5+12+12+15.

Here's my solution:
%w(abc abb aba).sort_by{|w| w.upcase.split(//).inject(0){|n,c| n+(c[0] - ?@)} }
=> ["aba", "abb", "abc"]


...I just refereshed my email, and I see that Holger Mack has
beat me to a reply. I didn't have a follow-up challenge ready,
so I'll just issue this meta challenge instead:

Look back over the set of one-liner challenges so far which
have gone unanswered and pick one.................

(As of this writing these include, Daniel Moore's "Print out a
Serpinski carpet"; James Gray's "Provide a one-liner that can
wrap a body of text at a requested maximum length." [assuming
strict requirements on maximum length], and, Holger Mack's
"Write a function per(n) which returns the periodicity of 1/n."


Regards,

Bill
 
M

Matthew Moss

Write a function per(n) which returns the periodicity of 1/n, i.e.
=A0 per(3) =3D> 1
=A0 per(4) =3D> 0
=A0 per(7) =3D> 6
=A0 per(11) =3D> 2

I think you're going to have to explain what periodicity is, or
provide a link... I've no clue.
 
J

James Coglan

[Note: parts of this message were removed to make it a legal post.]
Ready? Here goes. First problem...
You should know this pattern well:
[:eek:ne, "two", 4] * 3
=> [:eek:ne, "two", 4, :eek:ne, "two", 4, :eek:ne, "two", 4]

Write a single line method on Array that does this instead:
[:eek:ne, "two", 4].repeat(3)
=> [:eek:ne, :eek:ne, :eek:ne, "two", "two", "two", 4, 4, 4]



module Enumerable
def repeat(n = 1)
map { |e| [e] * n }.inject { |a,b| a + b }
end
end
 
M

Matthew Moss

I didn't really have a problem in mind, but here's an easy one: Write an = []=3D
method to solve the following:

obj =3D YourClass.new
obj['answer'] =3D 42
obj.answer =A0# =3D> 42


I'm no metaprogramming wizard... I keep trying variations until it
works. :D This seems to work.

class YourClass
def []=3D(f, v)
class << self; self end.instance_eval{ attr_accessor f };
instance_eval "@#{f}=3Dv"
end
end
 
J

James Coglan

[Note: parts of this message were removed to make it a legal post.]
New puzzle: Provide a one-liner that can wrap a body of text at a
requested maximum length.



A first guess... this destroys all original whitespace in the string,
currently trying to fix that.

class String
def line_wrap(n = 80)
split(/\s+/).inject{ |s,w| s + ("#{s.split("\n").last} #{w}".size > n ?
"\n" : " ") + w }
end
end
 
M

Matthew Moss

I'm no metaprogramming wizard... I keep trying variations until it
works. =A0:D =A0This seems to work.

class YourClass
=A0 def []=3D(f, v)
=A0 =A0 class << self; self end.instance_eval{ attr_accessor f };
instance_eval "@#{f}=3Dv"
=A0 end
end

Oops... I forgot to put up a new one-liner question! (Don't forget you
guys!!!)

Here's something simple: define method roll(n, s) to roll a s-sided
die n times and display a bar graph of the results. So roll(20, 4)
might look like this:

1|#####
2|#####
3|######
4|####
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top