#!/usr/bin/env ruby
#
# find_first_singleton.rb
#
# Given a string, find the first character that appears only once in the
# string. For instance, given the string “aabbcddd”, the first character
# that appears only once is the “c” found at the 4th character in the
# string, counting from 0. Be sure that your program properly handles the
# case that all characters appear more than once.
# % find_first_singleton -unrepeated-char 'somestring'
# o
# String.each_char_with_index {|c| code block with #c }
class String
def each_char_with_index
x = 0
while x < self.length do
char = self[x,1]
yield [char, x]
x += 1
end
end
# String.find_first_singleton(char) => [char, index] or nil
def find_first_singleton
letters = {} # hash of letters & occurences
self.each_char_with_index do |letter, x|
letters[letter] ||= 0
letters[letter] += 1
end
# all letters counted; find the first with count == 1
self.each_char_with_index do |letter, x|
return [letter, x] if letters[letter] == 1
end
nil
end
end # String enhancement
# [letter, index].pretty => "#{letter} at #{index}"
class Array
# [x, y].compare([r, s])
def compare(pair)
s, x = pair
return true if self.nil? && s.nil?
return false if self.nil?
self[0] == s && self[1] == x
end
def pretty
self.nil? ? 'nil' : self[0].to_s + ' at ' + self[1].to_s
end
end
class NilClass
def pretty
'nil'
end
end
def run_tests
tests = [ ['foo', ['f', 0]],
['foobar', ['f', 0]],
['oofbar', ['f', 2]],
['foofbar', ['b', 4]],
['foofbab', ['a', 5]],
['foofbob', [ nil ]],
['bar', ['b', 0]],
['barboy', ['a', 1]],
['barfbag', ['r', 2]],
['barfbar', ['f', 3]],
['barffrab', [ nil ]]
]
testc = 0
while testc < tests.size do
instr, answer = tests[testc]
testc += 1
printf "Test %02d: %10s => ", testc, instr
result = instr.find_first_singleton
if answer.compare(result)
puts "OK: #{result.pretty}\n"
else
puts "Failed: got #{result.pretty}; should be #{answer.pretty}"
end
end
exit
end # run_tests
if ARGV.size < 1 # if no args, run tests
run_tests
else
str = ARGV.shift # get the argument
puts "Input: #{str}"
puts str.find_first_singleton.pretty
end
exit