Here is my quick solution to quiz #83.
First I find all possible abbreviations, then try to find unique ones
for each string. If this isn't possible, then it tries for at least a
different abbreviation for each string. Finally, it falls back to the
heighest weighted abbreviation.
Weighting is currently a bit simplistic, and could probably be improved.
Weight is increased for
A) including the first character
B) cutting out 'word boundary' characters (' ', '_', '-', '.')
···
--
Brian Mattern
#Code below:
require 'pp'
module Compressor
# gets all compressed versions of str
def self.compress(str, len, ellipses = '...')
len = len.to_i
return case
when str.size <= len
[str]
else
ret = []
weight = {}
cutout = str.size - len + ellipses.size - 1
(0..(len-ellipses.size)).to_a.each do |i|
a = str.dup
a[i..(i + cutout)] = ellipses
w = 0
w += 1 if i > 0
[' ', '_', '-', '.'].each do |c|
w += 1 if str[i..(i+cutout)].include?(c)
end
ret << a
weight[a] = w
end
ret.sort{|s1, s2| weight[s2] <=> weight[s1] }
end
end
def self.compress_array(arr, len, ellipses = '...')
candidates = {}
arr.each { |s| candidates[s] = self.compress(s, len, ellipses) }
results = {}
candidates.each { |k, v|
# first try to find a completely unique abbreviation
results[k] = v.find { |s|
candidates.all? { |k2, v2| k2 == k or !v2.include?(s)}
}
# if none was found, just pick one that's different from the other chosen ones
results[k] = v.find { |s| !results.values.include?(s) } if results[k].nil?
# if we still don't have one, pick the first one (heighest weighted)
results[k] = v.first if results[k].nil?
}
arr.collect{ |s| results[s] }
end
end
class Array
def compress(len = 10)
Compressor.compress_array(self, len)
end
end
pp ARGV[1..-1].compress(ARGV[0])