views:

48

answers:

4

What's the simplest way to limit an array of words such that the resulting array, when the words are joined, is less than 40 characters? Something that acts like this:

words = ["ruby", "rails", "jquery", "javascript", "html"]
words.join.length #=> 29
words.join(", ").length #=> 37
words = ["ruby", "rails", "jquery", "javascript", "html", "css", "api"]
words.join.length #=> 35
words.join(", ").length #=> 47
words.chunk(:max_chars => 40) #=> ["ruby", "rails", "jquery", "javascript", "html"]

Thanks!

Update

Got this so far:

def chop(array, separator = "", max = 40)
  result = []
  array.each do |word|
    break if (result.join(separator).length + word.length > max)
    result << word 
    result
  end
  result
end
+1  A: 

Here's a fun way, you need active support:

require 'active_support'
class Array
  def chunk(sep = "", max = 40)
    self.inject([]){|m,n| (m+[n]).sum(&:size)+sep.size*m.size-1<max ? m<<n : m}
  end
end

Now:

["ruby", "rails", "jquery", "javascript", "html", "css", "api"].chunk(", ") #=> ["ruby", "rails", "jquery", "javascript", "html"]
Jeremy
+1  A: 

A slight variation on yours:

result = input.inject([]){|r,word|r<<word if r*separator+word.length < max}
AShelly
+1  A: 

Too bad there is a fencepost condition, otherwise this would be a much cleaner code with the take_while method

def chop(array, separator = "", max_size = 40)
  so_far = 0
  sep = separator.size
  array.take_while{|word| (so_far += word.size + sep) <= max_size + sep }
end

It checks it is less or equals than max_size + sep to compensate we are adding a separator to every word, even though the last one doesn't need it.

Chubas
+1  A: 
def chop(arr, sep = "", max = 40)
  max += sep.size
  arr.take_while{|x| (max -= x.size + sep.size) >= 0 }
end
grddev