whirlwin
whirlwin

Reputation: 16521

Ternary operator

I have an array d = ['foo', 'bar', 'baz'], and want to put its elements together into a string delimited by , and and at the last element so that it will become foo, bar and baz.

Here is what I'm trying to do:

s = ''
d.each_with_index { |x,i|
  s << x
  s << i < d.length - 1? i == d.length - 2 ? ' and ' : ', ' : ''
}

but the interpreter gives an error:

`<': comparison of String with 2 failed (ArgumentError)

However, it works with += instead of <<, but the Ruby Cookbook says that:

If efficiency is important to you, don't build a new string when you can append items onto an existing string. [And so on]... Use str << var1 << ' ' << var2 instead.

Is it possible without += in this case?

Also, there has to be a more elegant way of doing this than the code above.

Upvotes: 1

Views: 745

Answers (3)

glenn mcdonald
glenn mcdonald

Reputation: 15478

So much simpler like this:

"#{d[0...-1].join(", ")} and #{d.last}"

Upvotes: 1

Andrew Grimm
Andrew Grimm

Reputation: 81450

I'd find

s << i < d.length - 1? i == d.length - 2 ? ' and ' : ', ' : ''

hard to read or maintain.

I'd probably change it to

join = case
when i < d.length - 2 then ", "
when i == d.length - 2 then " and "
when i == d.length then ""
end
s << join

Or possibly do

earlier_elements = d[0..-2].join(", ")
s = [earlier_elements, d[-1..-1]].join(" and ")

Or

joins = [", "] * (d.length - 2) + [" and "]
s = d.zip(joins).map(&:join).join

Upvotes: 4

Roland Mai
Roland Mai

Reputation: 31077

You're just missing some parenthesis:

    d = ['foo', 'bar', 'baz']
    s = ''
    d.each_with_index { |x,i|
      s << x
      s << (i < d.length - 1? (i == d.length - 2 ? ' and ' : ', ') : '')
    }

Upvotes: 5

Related Questions