Begin forwarded message: > From: Florian Gross <flgr / ccan.de> > Date: July 13, 2007 7:35:13 PM CDT > To: james / grayproductions.net > Subject: Re: Ruby quiz solution > Oh, and the current Ruby Quiz looks great! I'm looking forward to > the solutions already. The simplest ones always have the broadest > range of solutions which makes them especially interesting. > > Just so I don't forget to submit my solution in time, here it is: > > > class Array > def each_cont_sub_array() > return enum_for(__method__) unless block_given? > > 0.upto(size - 1) do |start| > 1.upto(size - start) do |length| > yield self[start, length] > end > end > end > end > > [-1, 2, 5, -1, 3, -2, 1].each_cont_sub_array.max_by { |ary| > ary.inject(&:+) } # => [2, 5, -1, 3] > > > I decided to make it depend on 1.9, because I was too lazy to > include max_by and Symbol#to_proc. > Once that dependency was there I could shamelessly start to use > more features of 1.9. > (I think that the first line of each_contiguous_sub_array might > eventually become an idiom. :)) > > Other than that, it is pretty boring and straightforward. > > Oh, and the whole thing gets more interesting when you start > replacing :+ with :* and max_by with min_by... :) > > [-1, 2, 5, -1, 3, -2, 1].each_cont_sub_array.min_by { |ary| > ary.inject(&:+) } # => [-2] > [-1, 2, 5, -1, 3, -2, 1].each_cont_sub_array.max_by { |ary| > ary.inject(&:*) } # => [2, 5, -1, 3, -2] > [-1, 2, 5, -1, 3, -2, 1].each_cont_sub_array.min_by { |ary| > ary.inject(&:*) } # => [-1, 2, 5, -1, 3, -2] > > We can also make it find the shortest solution by changing the > max_by to max_by { |ary| [ary.inject(&:+), -ary.size] } and the > longest solution by changing it to max_by { |ary| [ary.inject(&:+), > +ary.size] }. > > > Here's my extension for matrix support: > > > class Array > def transpose_zip(&block) > first, rest = self[0], self[1 .. -1] > first.zip(*rest, &block) > end > end > > require 'matrix' > > class Matrix > def each_cont_sub_matrix(&block) > return enum_for(__method__) unless block_given? > > to_a.each_cont_sub_array do |rows| > rows.map { |row| row.each_cont_sub_array }.transpose_zip(&block) > end > end > end > > Matrix[ > [-1, +2, +5], > [-4, +5, -2], > [+8, +4, -3] > ].each_cont_sub_matrix.max_by { |ary| ary.flatten.inject(&:+) } # > => [[-1, 2], [-4, 5], [8, 4]] > > > Notes: > > A straight-forward solution without any clever algorithms. Just > building on top of the code we already have for Array. > > I define a custom transpose_zip() for two reasons: > a) transpose() can't yield its values (always constructs an array). > b) transpose() won't work when the inner elements are enumerators. > The code can be made shorter, but more inefficient, by using the > built-in transpose. > > Matrix#each_cont_sub_matrix yields nested arrays. Could be fixed to > yield Matrix objects, but then we need a to_a call before the flatten. > > Matrix#each_cont_sub_matrix needs to call to_a. This would be nicer > if there was a RandomAccess mix-in where we could centrally define > each_cont_sub_array() for both Array and Matrix. > > The method names are a bit long. The '_cont' could probably be > dropped. > > Kind regards, > Florian Gross