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

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

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

Challenge:
  Print out a Serpinski carpet.

···

On Fri, Sep 19, 2008 at 4:43 PM, Matthew Moss <matthew.moss@gmail.com> wrote:

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

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/&gt;\.

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:

   > [: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]

--
-Daniel

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[y] # => 7

James Edward Gray II

···

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

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]

# 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

···

From: "Matthew Moss" <matthew.moss@gmail.com>

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

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]

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

class Array
  # the classic
  def repeat(n)
    r = []; each { |e| n.times { r << e } }; r
  end

  # the nice
  def repeat(n)
    inject([]) { |a,e| a.concat [e]*n }
  end

  # the probably most efficient
  def repeat(n)
    Array.new(size*n) { |i| self[i/n] }
  end
end

# next challenge: return the power set of an Array's elements
# (my solution: https://gist.github.com/e05c3be86abf74b44853)

Too many solvers not providing additional problems!

Here's another... Assuming you have an array of numeric data, write a
method that returns an array of progressive sums. That is:

    prog_sum( [1, 5, 13, -6, 20] ) => [1, 6, 19, 13, 33]

Technically not one line, but it's under 80 chars and is recursive...

def f n;self.zip(n==2?self:f(n-1));end;def repeat n;f(n).flatten;end

...doesn't work for n < 2

Offered quiz is a no-brainer; mostly for golfing...

Given an epsilon, compute PI to that precision.

Todd

Summary coming late today.

Here's mine:
def repeat(i)
  self.map {|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

···

On Fri, Sep 19, 2008 at 9:21 PM, Daniel Moore <yahivin@gmail.com> wrote:

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

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[y] # => 7

How about

def (i)
  @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 ruby-talk@ruby-lang.org 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

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

···

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

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

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.

# next challenge: return the power set of an Array's elements
# (my solution:https://gist.github.com/e05c3be86abf74b44853\)

I'm not sure that providing your succinct solution right alongside the
challenge will encourage additional solutions. :slight_smile:

Too many solvers not providing additional problems!

Here's another... Assuming you have an array of numeric data, write a
method that returns an array of progressive sums. That is:

   prog_sum( [1, 5, 13, -6, 20] ) => [1, 6, 19, 13, 33]

def prog_sum(ary)
  ary.inject([0, ]) {|(s, a), i| [s+i, a<<(s+i)]}.last
end

Followon: Given an s-expression, print it out as a tree, where [:a,
:b, :c, :d] is the node with parent a and children b, c and d

[:foo, [:bar, [:baz, :quux], :hello, :world], :done] #=>

foo

-- bar
   > -- baz
   > > -- quux
   > -- hello
   > -- world
-- done

martin

···

On Mon, Sep 22, 2008 at 2:07 PM, Matthew Moss <matthew.moss@gmail.com> wrote:

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 Fri, Sep 19, 2008 at 6:53 PM, Patrick Doyle <wpdster@gmail.com> wrote:

On Fri, Sep 19, 2008 at 9:21 PM, Daniel Moore <yahivin@gmail.com> wrote:

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

Here's mine:
def repeat(i)
self.map {|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

--
-Daniel

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]}}.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 Friday 19 September 2008 21:11:21 Patrick Doyle wrote:

> 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[y] # => 7
>
How about

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

James Gray 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.

···

--
Jabber: sepp2k@jabber.org
ICQ: 205544826

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