17
\$\begingroup\$

Should take an array such as ['dog', 'cat', 'bird', 'monkey'] and return 'dog, cat, bird and monkey'.

Looking for a more elegant solution.

def self.english_join(array)
  return nil if array.nil?
  return array[0] if array.length == 1
  return array[0..-2].join(', ') + " and " + array[-1] if array.length > 1
end
\$\endgroup\$

3 Answers 3

29
\$\begingroup\$

Rails (actually ActiveSupport, part of the Rails framework) offers a very nice Array#to_sentence method.

If you are using Rails or ActiveSupport, you can call

['dog', 'cat', 'bird', 'monkey'].to_sentence
# => "dog, cat, bird, and monkey"

The method is automatically customized according to I18n settings. For example, in Italy you should omit the last comma before the and.

['dog', 'cat', 'bird', 'monkey'].to_sentence
# => "dog, cat, bird e monkey"

If you want something without depending on ActiveSupport, you can start using the method source code.

This is just an example

class Array
  def to_sentence
    default_words_connector     = ", "
    default_two_words_connector = " and "
    default_last_word_connector = ", and "

    case length
      when 0
        ""
      when 1
        self[0].to_s.dup
      when 2
        "#{self[0]}#{options[:two_words_connector]}#{self[1]}"
      else
        "#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
    end
  end
end
\$\endgroup\$
3
  • \$\begingroup\$ .to_sentence is literally magic. \$\endgroup\$
    – drusepth
    Commented Jul 9, 2014 at 15:52
  • \$\begingroup\$ You've forgotten to add a options parameter to the method. \$\endgroup\$
    – m26a
    Commented May 2, 2019 at 23:26
  • \$\begingroup\$ This is how I discovered .to_sentence and oh my goodness, this made my whole day. \$\endgroup\$ Commented May 9, 2021 at 22:52
5
\$\begingroup\$
def english_join(array = nil)
  return array.to_s if array.nil? or array.length <= 1
  array[0..-2].join(", ") + " and " + array[-1]
end

A similar but different approach. Combines the joining of a slice of the array with a string append to get the last "and" part.

\$\endgroup\$
2
  • 3
    \$\begingroup\$ However, it might be better to write the last line as "#{array[0..-2].join(", ")} and #{array.last}". "#{}" creates fewer String objects than +, and so should generally be preferred. \$\endgroup\$ Commented Nov 9, 2011 at 16:13
  • 2
    \$\begingroup\$ Also, this doesn't get the comma before the "and". \$\endgroup\$ Commented Nov 9, 2011 at 16:14
2
\$\begingroup\$
def self.english_join(array = nil)
  return array.to_s if array.nil? or array.length <= 1
  array[-1] = "and #{array[-1]}"
  array.join(', ')
end

A different way but not much better. Returns an empty string instead of nil if the array is empty. Someone will chime in with a sweet to_sentence method.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.