Skip to content
mengfung.com
writing

Ruby Job Interview Question

 ·  5 min read

This one was quite interesting, this isn’t the actual version I turned in.

I was sent a unit test and was asked to generate the class for it, I actually created a recursive and non-recursive solution the second time around. The first time I pretty much blew it, I should have taken a break and not have done it right after a code fest of PHP.

I am pretty proud of myself, I think ruby is pretty awesome just look I figured out how to solve this problem in 3 different ways, in a span of 5-6 hours total.

I think my final solution is way prettier, I extended the Array class and added a module. Just look at the method call in def partition(size), pretty dayam clean.

module Summable
  def sum
    inject {|v,n| v+n}
  end
end
class Array
  include Summable
  def partition(size, result = [])
    chunks = (self.size / size.to_f).ceil
 
# this will give you a delta of 1 for subset size due to recursion 
# still passes test
 
    if size == 1
      result << self
    else
      a = Array.new(chunks)
      b = self.slice!(0,chunks)
      result <<  a[0, b.size] = b
      partition(size - 1, result)
    end  
 
# this will always give you subsets equal to each other
#    1.upto(size) do |i|
#      a = Array.new(chunks)
#      b = self.slice!(0,chunks)
#      result <<  a[0, b.size] = b
#    end
 
    return result
  end
end
 
class YPSet
  # init class variables
	def initialize(*args)
          @collection = []
          args.each {|arg| @collection << arg.to_i}
          @collection_size = @collection.size 
	end
 
	# returns [float] the average from the set
	def average
	  result = 0.0
	  sum = @collection.sum.to_f
	  result = sum / @collection_size
	  return result
	end
 
	# returns [float] the median from the set
	def median
	  @collection.sort!
	  result = 0.0
	  mid = @collection_size / 2
 
	  # check to see if set has even or odd number of items
	  case is_even(@collection_size)
    when true # is even
      result = (@collection[mid] + @collection[mid - 1]) / 2.0
    else # is odd
      result = @collection[mid]
    end
 
    return result
	end
 
	def partition(size)
		return @collection.partition(size)
  end
 
  # all for #4
 
  def odd_set
    result = []
 
    0.upto(@collection_size-1) do |i|
      if !is_even(@collection[i])
        result << @collection[i]
      end
    end
 
    return result
  end
 
  def even_set
    result = []
 
    0.upto(@collection_size-1) do |i|
      if is_even(@collection[i])
        result << @collection[i]
      end 
    end
 
    return result
  end
 
  def how_many_even
    return even_set().size
  end
 
  def how_many_odd
    return odd_set().size
  end
 
  #converts the entire sets items from int to bin
  def convert_set_to_binary
    result = []
 
    0.upto(@collection_size-1) do |i|
      result << convert_to_binary(@collection[i])
    end
 
    return result
  end
 
  # convert number to binary
  def convert_to_binary(number)
    number = number.to_i
    result = ""
 
    if (number == 0)
      return 0
    end
 
    while (number != 0)
      result = (number % 2).to_s + result
      number = number / 2
    end
 
    return result
  end
 
  # is number even
  def is_even(number)
    result = number.to_i % 2 == 0 ? true : false
    return result
  end
 
  def range()
		first = @collection[0]
		last = @collection[@collection_size - 1]
 
		return (last - first)
	end
end

Here’s my unit test

require 'test/unit'
require 'ypset'
 
class YPSetTest < Test::Unit::TestCase
 
  def setup
 
  end
 
  def test_should_calculate_average
    assert_equal 6, YPSet.new(8, 10, 2, 6, 4).average
    assert_equal 5.5, YPSet.new(10, 11, 0, 1).average
  end
 
  # The median is the middle value in a set of values.  If there are
  # an even number of values, it should be the average of the two middle
  # values
  def test_should_calculate_median
    assert_equal 6, YPSet.new(8, 10, 2, 6, 4).median
    assert_equal 4.5, YPSet.new(10, 0, 1, 9, 8, 1).median
  end
 
  # for #3 you need to test for strings
 
  def test_should_calculate_median_strings
    assert_equal 6, YPSet.new("8", "10", 2, "6", 4).median
    assert_equal 4.5, YPSet.new(10, "0", "1", "9", "8", "1").median
  end
 
  def also_if_nil_set
    assert_equal 0, YPSet.new().average
    assert_equal 0, YPSet.new().median
  end
 
  def test_should_split_into_evenly_sized_subsets
    values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
 
    subsets = YPSet.new(*values).partition(3)
    assert_equal 3, subsets.length
    subsets.each do |subset|
      assert_equal 5, subset.length
    end
    assert_equal values.length, subsets.flatten.length   
 
    values << 16
    subsets = YPSet.new(*values).partition(3)
    assert_equal 3, subsets.length
    subsets.each do |subset|
      assert_in_delta 5, subset.length, 1
    end
    assert_equal values.length, subsets.flatten.length   
 
    values = Array.new(18923) {|i| i}
    subsets = YPSet.new(*values).partition(124)
    assert_equal 124, subsets.length
    subsets.each do |subset|
      assert_in_delta 152, subset.length, 1
    end
    assert_equal values.length, subsets.flatten.length
 
  end
 
  def test_range 
    values = Array.new(18923234234234234234234234) {|i| i}
    assert_raise(RuntimeError) { YPSet.new(*values)}
  end
 
  # for #4
 
  def test_is_even
    assert_equal true, YPSet.new().is_even(2)
    assert_equal false, YPSet.new().is_even(1)
    assert_equal true, YPSet.new().is_even("2")
    assert_equal false, YPSet.new().is_even("1")
  end
 
  def test_even_set
    assert_equal [2,4,6], YPSet.new(2,3,4,5,6,7).even_set
    assert_equal [], YPSet.new(1,3,5,7,9,11).even_set
  end
 
  def test_odd_set
    assert_equal [1,3,5,7,9], YPSet.new(1,2,3,4,5,6,7,8,9).odd_set
    assert_equal [1], YPSet.new(1,2,4,6,8).odd_set
  end
 
  def test_how_many_odd
    assert_equal 5, YPSet.new(1,2,3,4,5,6,7,8,9).how_many_odd
  end
 
  def test_how_many_even
    assert_equal 4, YPSet.new(1,2,3,4,5,6,7,8,9).how_many_even
    assert_equal 0, YPSet.new(1,3,5,7,9).how_many_even
    #strings 
    assert_equal 0, YPSet.new(1,3,"5","7","9").how_many_even
  end
 
  def test_convert_to_binary
    assert_equal "101", YPSet.new().convert_to_binary("5")
    assert_equal "11", YPSet.new().convert_to_binary(3)
    assert_equal "10", YPSet.new().convert_to_binary(2)
  end
 
  def test_convert_set_to_binary
    assert_equal ["1","10","11","100","101"], YPSet.new(1,2,3,4,5).convert_set_to_binary
  end
 
  def test_range
    assert_equal 9, YPSet.new(1,10).range
  end
end

for the partition part here is my first soltuion: See the instants variable @ and ; this was due to me spending all day before taking the test working in PHP, ugly isn’t it? I kept looking at the code thinking “This looks like PHP not Ruby!”, there had to be a better solution to this problem, a Ruby way! So I actually took a breath and read some Ruby Docs on Arrays and Sets and came on the above solution.

	def partition(size)
		@length = @numbers.length;
		@mid = (@length / size);
		@parts = [];
		@start = 0;
 
		1.upto(size) do |i|
			@last = @start+@mid;
			@last = @last-1 unless @length%size >= i;
			@parts << @numbers[@start..@last] || [];
			@start = @last+1;
		end
 
		return @parts
	end