One-Liners Mashup (#177 again)

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

The three rules of Ruby Q. 2:

  1. This week only – no waiting period!

  2. Support Ruby Q. 2 by submitting ideas as often as you can! (A
    permanent, new website is in the works for Ruby Q. 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 T. 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:

> [:one, "two", 4] * 3
=> [:one, "two", 4, :one, "two", 4, :one, "two", 4]

Write a single line method on Array that does this instead:

> [:one, "two", 4].repeat(3)
=> [:one, :one, :one, "two", "two", "two", 4, 4, 4]

And if it wasn’t clear from the very top… no no-spoiler period this
week.

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

Challenge:
Print out a Serpinski carpet.

On Fri, Sep 19, 2008 at 9:21 PM, Daniel M. [email protected] wrote:

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

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

How about

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

Post your solution AND a followup problem for others to solve.
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 [email protected] 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

It splats an array into it’s components:

. 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

On Sep 19, 2008, at 6:43 PM, Matthew M. wrote:

First problem…
You should know this pattern well:

[:one, “two”, 4] * 3
=> [:one, “two”, 4, :one, “two”, 4, :one, “two”, 4]

Write a single line method on Array that does this instead:

[:one, “two”, 4].repeat(3)
=> [:one, :one, :one, “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 G. II

On Friday 19 September 2008 21:11:21 Patrick D. wrote:

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

How about

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

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

class Data2D
def
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

On Sep 19, 2008, at 9:34 PM, David M. wrote:

end

Curses! You beat me to it, so I wrote a more complex solution:
lookup, as no array splicing is done.
When I wrote the problem, I was thinking of this solution:

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

James Edward G. II

On Sep 19, 2008, at 9:32 PM, Bill K. wrote:

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

From: “Matthew M.” [email protected]

=> [:one, :one, :one, "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 [:one, “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

James G. wrote:

New puzzle: Provide a one-liner that can wrap a body of text at a
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 80
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.

2008/9/20 Sebastian H. [email protected]

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.length64 <=>
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 :wink:


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

From: “Sebastian H.” [email protected]

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

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 M. 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 M.'s “Print out a
Serpinski carpet”; James G.'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 M.'s
“Write a function per(n) which returns the periodicity of 1/n.”

Regards,

Bill

From: “Bill K.” [email protected]

From: “Sebastian H.” [email protected]

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…

Oops - My apologies – I found the post:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/287353

… and the solution therein appears to have the same single-word
breaking restrictions as Sebastion mentioned above.

Regards,

Bill

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

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

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

I’m no metaprogramming wizard… I keep trying variations until it
works. :smiley: This seems to work.

class YourClass
def []=(f, v)
class << self; self end.instance_eval{ attr_accessor f };
instance_eval “@#{f}=v”
end
end

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

=> [:one, :one, :one, “two”, “two”, “two”, 4, 4, 4]
module Enumerable
def repeat(n = 1)
map { |e| [e] * n }.inject { |a,b| a + b }
end
end

Challenge:
Print out a Serpinski carpet.

Here ya go. Non-negative parameter to the function is recursion depth,
so should be 0 for the “null 1x1 carpet”, 1 for the 3x3, 2 for the
9x9, etc. This is golfed, and probably a bit more than 80 chars
(gonna wrap in email, I bet).

def carpet(n)
def k(s,x,y) (s<=3||k(s/3,x/3,y/3))&&!(x%3==1&&y%3==1)
end;s=3**n;s.times{|y|s.times{|x| print k(s,x,y)?"#":" "};puts}
end

Followup: Make my solution shorter. (There’s got to be something nicer
than using times twice and print once.