This took me less than a minute to write, but I don't know if it's as
elegant as it could be. Are there more "Ruby-like ways(tm)" to write
this?
def stringify array
return array[0] if array.size == 1
string = ""
array.each_with_index do |element, index|
case index
when array.size - 1 # last item
string += " and #{element}"
when 0
string += "#{element}"
else
string += ", #{element}"
end
end
string
end
irb(main):048:0> stringify
=> ""
irb(main):045:0> stringify %w{foo}
=> "foo"
irb(main):046:0> stringify %w{foo bar}
=> "foo and bar"
irb(main):047:0> stringify %w{foo bar baz}
=> "foo, bar and baz"
Note, I don't claim that this is necessarily more rubyish.
Kind regards
robert
···
2009/12/10 Aldric Giacomoni <aldric@trevoke.net>:
This took me less than a minute to write, but I don't know if it's as
elegant as it could be. Are there more "Ruby-like ways(tm)" to write
this?
def stringify array
return array[0] if array.size == 1
string = ""
array.each_with_index do |element, index|
case index
when array.size - 1 # last item
string += " and #{element}"
when 0
string += "#{element}"
else
string += ", #{element}"
end
end
string
end
This took me less than a minute to write, but I don't know if it's as
elegant as it could be. Are there more "Ruby-like ways(tm)" to write
this?
array.inspect
Of course, that won't get you the "and".
def stringify array
return array[0] if array.size == 1
string = ""
array.each_with_index do |element, index|
case index
when array.size - 1 # last item
string += " and #{element}"
when 0
string += "#{element}"
else
string += ", #{element}"
end
end
string
Interesting question.
class Array # or perhaps module Enumerable
def stringify(conjunction = 'and', separator = ', ')
if self.size <= 1
return self.to_s
elsif self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ' '
array.join separator # proper English usage has comma before 'and'
end
end
end
def stringify array
string = ""
array.each_with_index do |element, index|
string << case index
when 0
""
when (as=array.size) - 1 # last item
(as < 3 ? "" : "," ) + " and "
else
", "
end << "#{element}"
end
string
end
s=
%w(this is a test). each do |element|
p stringify(s<<[element])
end
C:\prg>ruby -W0 test3.rb
"this"
"this and is"
"this, is, and a"
"this, is, a, and test"
best regards -botp
···
On Thu, Dec 10, 2009 at 10:15 PM, Aldric Giacomoni <aldric@trevoke.net> wrote:
This took me less than a minute to write, but I don't know if it's as
elegant as it could be. Are there more "Ruby-like ways(tm)" to write
this?
def stringify array
return array[0] if array.size == 1
string = ""
array.each_with_index do |element, index|
case index
when array.size - 1 # last item
string += " and #{element}"
when 0
string += "#{element}"
else
string += ", #{element}"
end
end
string
end
--
This took me less than a minute to write, but I don't know if it's as
elegant as it could be. Are there more "Ruby-like ways(tm)" to write
this?
def stringify array
return array[0] if array.size == 1
string = ""
array.each_with_index do |element, index|
case index
when array.size - 1 # last item
string += " and #{element}"
when 0
string += "#{element}"
else
string += ", #{element}"
end
end
string
end
Couldn’t resist:
def stringify a
a.size < 2 ? a.first.to_s : a[0..-2].join(', ') + " and #{a.last}"
end
Note, I don't claim that this is necessarily more rubyish.
Your solutions *stink* of LISP, but maybe that's only because you're ..
er.. processing lists.
I like your first one - it feels more elegant than mine. The second one
feels a little too convoluted. I also find that using 'slice' is too
wordy, and usually just settle for array[0...-1] or array[-2..-1] -- but
clearly that's just preference. Thanks for the further examples, I'll
remember them (and possibly even use them someday!)
class Array # or perhaps module Enumerable
def stringify(conjunction = 'and', separator = ', ')
if self.size <= 1
return self.to_s
elsif self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ' '
array.join separator # proper English usage has comma before 'and'
end
end
end
It is pretty, and (like Robert's solution) handles the case where the
array has no elements. I wouldn't put that into Enumerable though, not
sure how it would handle a hash, for instance
Do you think if / elsif / else is better in this situation than "case
self.size"? What about in general?
I know it's usually accepted that instead of several elsifs, one should
use 'case', but I usually try to avoid 'elsif' altogether.
On Thu, Dec 10, 2009 at 10:15 PM, Aldric Giacomoni <aldric@trevoke.net> wrote:
This took me less than a minute to write, but I don't know if it's as
elegant as it could be. Are there more "Ruby-like ways(tm)" to write
this?
def stringify array
return array[0] if array.size == 1
string = ""
array.each_with_index do |element, index|
case index
when array.size - 1 # last item
string += " and #{element}"
when 0
string += "#{element}"
else
string += ", #{element}"
end
end
string
end
--
just joing the fun of ruby,
C:\prg>cat test3.rb
def stringify array
string = ""
array.each_with_index do |element, index|
string << case index
when 0
""
when (as=array.size) - 1 # last item
(as < 3 ? "" : "," ) + " and "
else
", "
end << "#{element}"
end
string
end
s=
%w(this is a test). each do |element|
p stringify(s<<[element])
end
C:\prg>ruby -W0 test3.rb
"this"
"this and is"
"this, is, and a"
"this, is, a, and test"
Note, I don't claim that this is necessarily more rubyish.
Your solutions *stink* of LISP, but maybe that's only because you're ..
er.. processing lists.
Oh no. Pascal is responsible for lispish solutions - I'm not.
I like your first one - it feels more elegant than mine. The second one
feels a little too convoluted.
Yep.
I also find that using 'slice' is too
wordy, and usually just settle for array[0...-1] or array[-2..-1] -- but
clearly that's just preference.
I just felt #slice deserved a mention because it is so rarely seen.
Initially I also thought about using #slice! which cannot be done with
#. But then you would either modify the argument or have to dup the
Array.
Thanks for the further examples, I'll
remember them (and possibly even use them someday!)
You're welcome! Thanks for the opportunity to play around a bit.
class Array # or perhaps module Enumerable
def stringify(conjunction = 'and', separator = ', ')
if self.size <= 1
return self.to_s
elsif self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ' '
array.join separator # proper English usage has comma before 'and'
end
end
end
It is pretty, and (like Robert's solution) handles the case where the
array has no elements. I wouldn't put that into Enumerable though, not
sure how it would handle a hash, for instance
Do you think if / elsif / else is better in this situation than "case
self.size"?
Yes. case won't handle <= conditions AFAIK.
What about in general?
I know it's usually accepted that instead of several elsifs, one should
use 'case', but I usually try to avoid 'elsif' altogether.
Use whichever syntax is better suited to what you need. There's nothing
wrong with elsif IMHO.
That is a very good point, though it does handle ranges, so "case 0..1"
would fit this particular scenario.
Your elsif statement is probably better suited here though.
That is a very good point, though it does handle ranges, so "case 0..1"
would fit this particular scenario.
Your elsif statement is probably better suited here though.
If I'd remembered your point about ranges, I might have used case.
That point is not exactly true: while it doesn't out of the box, it
can easily be made to:
irb(main):001:0> ONE_OR_LESS = lambda {|n| n <= 1}
=> #<Proc:0x1014ed90@(irb):1 (lambda)>
irb(main):002:0> class <<ONE_OR_LESS; alias === ; end
=> nil
irb(main):003:0> 5.times {|i| case i; when ONE_OR_LESS then puts
"yow!" else puts "nah" end}
yow!
yow!
nah
nah
nah
=> 5
irb(main):004:0>
Apart from that, the length of an Array can as a minimum become only 0
so the same test can be done as
case array.size
when 0,1 # <= 1
...
when
...
end
Kind regards
robert
···
2009/12/10 Aldric Giacomoni <aldric@trevoke.net>:
Marnen Laibow-Koser wrote:
Yes. case won't handle <= conditions AFAIK.
That is a very good point, though it does handle ranges, so "case 0..1"
would fit this particular scenario.
Your elsif statement is probably better suited here though.
As written in "Programming Ruby 1.9",
You can really use case as if ... elsif ... else ... end
So, in our case:
if self.size <= 1
return self.to_s
elsif self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ' '
array.join separator # proper English usage has comma before 'and'
end
becomes:
case
when self.size <= 1
return self.to_s
when self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ' '
array.join separator # proper English usage has comma before 'and'
end
Well, that's not especially better I think, but it looks cool and a little
less 'procedural' to me.
Anyway, I'm wondering how case manage the comma(,), is it acting like a OR
on each of the elements? I thought first to Array#=== but that isn't
defined. So, is it sort of syntactic sugar ?
···
2009/12/10 Robert Klemme <shortcutter@googlemail.com>
2009/12/10 Aldric Giacomoni <aldric@trevoke.net>:
> Marnen Laibow-Koser wrote:
>>
>> Yes. case won't handle <= conditions AFAIK.
>
> That is a very good point, though it does handle ranges, so "case 0..1"
> would fit this particular scenario.
> Your elsif statement is probably better suited here though.
That point is not exactly true: while it doesn't out of the box, it
can easily be made to:
irb(main):001:0> ONE_OR_LESS = lambda {|n| n <= 1}
=> #<Proc:0x1014ed90@(irb):1 (lambda)>
irb(main):002:0> class <<ONE_OR_LESS; alias === ; end
=> nil
irb(main):003:0> 5.times {|i| case i; when ONE_OR_LESS then puts
"yow!" else puts "nah" end}
yow!
yow!
nah
nah
nah
=> 5
irb(main):004:0>
Apart from that, the length of an Array can as a minimum become only 0
so the same test can be done as
That is a very good point, though it does handle ranges, so "case 0..1"
would fit this particular scenario.
Your elsif statement is probably better suited here though.
That point is not exactly true: while it doesn't out of the box...
c:\>irb
irb(main):001:0> RUBY_VERSION
=> "1.8.7"
irb(main):002:0> 5.times { |a| case a; when 0..2 then puts "yow" else
puts "nah" end }
yow
yow
yow
nah
nah
=> 5
irb(main):003:0>
As written in "Programming Ruby 1.9",
You can really use case as if ... elsif ... else ... end
So, in our case:
if self.size <= 1
return self.to_s
elsif self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ' '
array.join separator # proper English usage has comma before 'and'
end
becomes:
case
when self.size <= 1
return self.to_s
when self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ' '
array.join separator # proper English usage has comma before 'and'
end
Thanks, I had forgotten about that too.
Well, that's not especially better I think, but it looks cool and a
little
less 'procedural' to me.
It's no less procedural, and in fact it uses another line of code for no
advantage that I can see.
If you truly want this to look less procedural, I think you'd need to
somehow implement a polymorphic dispatch based on Array.size...but let's
not go there.
Anyway, I'm wondering how case manage the comma(,), is it acting like a
OR
on each of the elements? I thought first to Array#=== but that isn't
defined. So, is it sort of syntactic sugar ?
Best,
···
2009/12/10 Robert Klemme <shortcutter@googlemail.com>