Home > database >  Short and efficient Ruby code for transforming array of words to shuffled and comma separated string
Short and efficient Ruby code for transforming array of words to shuffled and comma separated string

Time:11-06

I would like to transform such array:

["apple","banana","pineapple","plum","pear"]

to

I like plum, pineapple, banana, pear *and* apple.

My current code is like:

%Q{
   I like #{%w[apple banana pineapple plum pear].shuffle.yield_self{|q| [q[0..-2].join(", "),q[-1]].join(" and ") }}
  }

Is there any more %w[clever clean shorter efficient rubyesque].magic() approach?

CodePudding user response:

I don't know if this is more clever or cleaner, but here we go:

def to_sentence(ary)
  ary = ary.dup.shuffle
  [ary.pop, ary.join(', ')].reverse.join(' and ')
end

CodePudding user response:

I would like to offer two solutions. Neither mutates the array that is passed to the method as an argument.

arr = ["apple", "banana", "pineapple", "plum", "pear"]

#1

 def to_sentence(arr)
  *all_but_last, last = arr.shuffle
  all_but_last.join(', ') << ' and ' << last
end
to_sentence(arr)
  #=> "pear, plum, pineapple, apple and banana"
to_sentence(arr)
  #=> "banana, pear, pineapple, plum and apple"
to_sentence(arr)
  #=> "banana, plum, apple, pineapple and pear"
to_sentence(arr)
  #=> "banana, pineapple, pear, apple and plum"

#2

 def to_sentence(arr)
  arr.shuffle.join(', ').sub(/,(?!.*,)/, ' and')
 end
 to_sentence(arr)
   #=> "banana, plum, pear, apple and pineapple"
 to_sentence(arr)
   #=> "pear, plum, pineapple, banana and apple"
 to_sentence(arr)
   #=> "apple, pineapple, plum, pear and banana"
 to_sentence(arr)
   #=> "apple, plum, pear, pineapple and banana"

The regular expression matches a comma that is not followed later in the string by another comma (that is, it matches the last comma in the string). (?!.*,) is a negative lookahead.

The regular expression could also be written

/.*\K,/

.* matches any character other than line terminators, as many as possible (including commas), because * is by default greedy. \K then resets the start of the match to the current location in the string (right before the last comma) and discards any previously-consumed characters from the match that is returned. A comma is then matched, which necessarily is the last comma in the string.

  • Related