Nifty free tool for brushing up on Ruby skills

3 views
Skip to first unread message

google...@jamesgagne.com

unread,
Aug 14, 2011, 12:58:06 AM8/14/11
to LA Ruby Study Group, Cynthia Kiser
Dear Rubyists (Rubyistas? Ruby fans? Rubyphiles?),
Teach Me to Code has a neat, quick screencast about rubykoans.com, a
nifty site for deepening one's knowledge of Ruby. You download a group
of files that run tests. The tests fail until you insert the correct
Ruby code.

Here's the screencast describing rubykoans.com:
http://teachmetocode.com/screencasts/ruby-koans/

nate

unread,
Aug 16, 2011, 1:04:30 AM8/16/11
to LA Ruby Study Group
On the triangle problem, is there a better way to write

if a == b || b == c || c == a

I came up with

[a, b, c].all? { |side| side == a }

It's doesn't save any typing until you get past three values that need
to be compared

Nate

On Aug 13, 9:58 pm, "google_nos...@jamesgagne.com"

nate

unread,
Aug 16, 2011, 1:08:52 AM8/16/11
to LA Ruby Study Group
Forgot to ask if anyone knows an alternative to this one:

if a == b || b == c || c == a

Scott Mueller

unread,
Aug 16, 2011, 2:22:44 AM8/16/11
to laruby...@googlegroups.com
Hi Nate,

I'm not following the book club and don't know the triangle problem, but your answer below isn't correct.  You're only testing the values against a (including testing a against a).  If you're looking for a solution to test if any values are equal to each other in an arbitrary size set of values, you'll want to sort the values first and then compare them sequentially like this:

def anything_equal?(*values)
  values.sort.inject do |previous, current|
    if previous == current
      return true
    else
      current
    end
  end
  false
end

Bruce

unread,
Aug 16, 2011, 2:50:45 AM8/16/11
to LA Ruby Study Group
On Aug 15, 11:22 pm, Scott Mueller <sc...@gig.io> wrote:
>
> def anything_equal?(*values)
>   values.sort.inject do |previous, current|
>     if previous == current
>       return true
>     else
>       current
>     end
>   end
>   false
> end
>
Since a set is a collection of unique values:

require 'set'
def anything_equal?(*values)
values.size != values.to_set.size
end

Dan Loewenherz

unread,
Aug 16, 2011, 2:57:54 AM8/16/11
to laruby...@googlegroups.com
I prefer this solution. It uses the built-in combination method on the Array class.

values.combination(2).any? {|i,j| i==j}

Then you can monkey patch Array itself if you're really into this keystroke-saving thing.

class Array
  def anything_equal?
    self.combination(2).any? {|i,j| i==j}
  end
end

The result:

> [1,2,3].anything_equal?
=> false
> [1,1,3].anything_equal?
=> true

-Dan

Scott Mueller

unread,
Aug 16, 2011, 4:17:31 AM8/16/11
to laruby...@googlegroups.com
I like the monkey patching.  Though that solution seems less efficient as you might have to compare all possible pairs of values.

Scott Mueller

unread,
Aug 16, 2011, 4:50:52 AM8/16/11
to laruby...@googlegroups.com
That's pretty convenient!  I just looked at the source for Set's enum.to_set method.  Basically it adds the array's elements individually to a hash.  Certainly satisfies the original concern of saving typing.  But not so elegant given the different needs of a set and therefore inefficient underlying implementation.

On Mon, Aug 15, 2011 at 11:50 PM, Bruce <bruce...@gmail.com> wrote:

Meng

unread,
Aug 16, 2011, 9:27:30 AM8/16/11
to LA Ruby Study Group
I placed all sides into an array

case [a, b, c].uniq
when 3
when 2
when 1
end

Meng

unread,
Aug 16, 2011, 9:31:04 AM8/16/11
to LA Ruby Study Group
case [a, b, c].uniq.size

Dan Loewenherz

unread,
Aug 16, 2011, 11:23:43 AM8/16/11
to laruby...@googlegroups.com
Actually, combination only shoots out distinct pairs.

> [1,2,3,4].combination(2).to_a
=> [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]

Bruce Hobbs

unread,
Aug 16, 2011, 12:08:28 PM8/16/11
to laruby...@googlegroups.com
On Tue, Aug 16, 2011 at 6:31 AM, Meng <meng...@gmail.com> wrote:
case [a, b, c].uniq.size

That certainly simplifies it further:
def anything_equal?(*values)
 values.size != values.uniq.size
end

Meng Fung

unread,
Aug 16, 2011, 12:12:45 PM8/16/11
to laruby...@googlegroups.com
if you want to keep track of sides and duplicates.

sides = [a, b, c].inject(Hash.new(0)) { |h, side| h[side] += 1; h}

case sides.size
when 3
when 2
when 1
end

Scott Mueller

unread,
Aug 16, 2011, 12:52:21 PM8/16/11
to laruby...@googlegroups.com
Yes, I meant all possible unique pairs.  If there are no equal pairs, it will have to go through n*(n-1)/2 pairs.  Exponentially worse performance as the set gets bigger.

nate

unread,
Aug 16, 2011, 1:44:02 PM8/16/11
to LA Ruby Study Group
The triangle problem is in the ruby koans code. Given three values,
the code is supposed to determine if the the triangle sides make a
scalene, isosceles or equilateral triangle, or if it's not a legal
triangle.

I meant to indicate that I wanted all values equal, not just any two
values.

a == b && b == c && c == a

I was hoping for parallel comparison, like a == b == c

I also needed the other answer, so thanks for all the replies.

On Aug 15, 11:22 pm, Scott Mueller <sc...@gig.io> wrote:

Bruce Hobbs

unread,
Aug 16, 2011, 6:49:37 PM8/16/11
to laruby...@googlegroups.com
On Tue, Aug 16, 2011 at 10:44 AM, nate <nate.b...@gmail.com> wrote:
The triangle problem is in the ruby koans code. Given three values,
the code is supposed to determine if the the triangle sides make a
scalene, isosceles or equilateral triangle, or if it's not a legal
triangle.

I meant to indicate that I wanted all values equal, not just any two
values.

a == b && b == c && c == a

This is probably a stupid question, but isn't it sufficient to just check that the first two comparisons are true? If that's the case then there's another, admittedly longer, alternative:

a == b ? b == c : false 

I was hoping for parallel comparison, like a == b == c

Unfortunately the standard == operator/method returns a boolean and overriding that probably wouldn't be an optimal solution. If the sides are all Fixnums you could override a much less-used operator/method, say =~, for example:

class Fixnum
  def =~(b,c)
    [self,b,c].uniq.size == 1
  end
end

I can't figure out how to get the usual syntactic sugar, but this seems to work:

a.=~(b,c)

nate

unread,
Aug 17, 2011, 2:25:25 PM8/17/11
to LA Ruby Study Group
It wasn't really about saving keystrokes, it was about making multiple
comparisons scalable.

Nate

nate

unread,
Aug 17, 2011, 2:35:23 PM8/17/11
to LA Ruby Study Group
So my two favorite answers are:

"a == b ? b == c: false" and "case sides_array.uniq.size"

I wasn't thinking about the redundancy of checking a against c if the
first two were true. The case is great because it captures all three
triangle option with one comparison.

Nate

nate

unread,
Aug 18, 2011, 12:21:27 AM8/18/11
to LA Ruby Study Group
Here's the class solution

class Triangle
def initialize(a, b, c)
@sides = [a, b, c]
end

def is_valid?
shortest, middle, longest = @sides.sort
shortest + middle > longest
end

def is_scalene?
@sides.uniq.count == 3
end

def is_isoceles?
@sides.uniq.count == 2
end

def is_equilateral?
@sides.uniq.count == 1
end

def triangle_type
return :invalid unless is_valid?
return :scalene if is_scalene?
return :isoceles if is_isoceles?
:equilateral
end
end
Reply all
Reply to author
Forward
0 new messages